Как написать мессенджер на kotlin
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Mesibo Messenger is an open-source app with real-time messaging, voice and video call features. This repo contains the source code for Mesibo Messenger App for Android. The GitHub repository for iOS version is here.
Latest versions are also available through Google Play Store and Apple App Store:
Downloading the Source Code
Clone the Repository (Recommended)
If you have git installed, this is a recommended approach as you can quickly sync and stay up to date with the latest version. This is also a preferred way of downloading the code if you decide to contribute to the project.
To download, open a terminal and issue following commands:
Download the code as a zip file
You can also download the complete Android Messenger source code as a zip file. Although simple, the downsize of this approach is that you will have to download the complete source code everytime it is updated on the repository.
Whatever approach you take to download the code, it is important to stay up-to-date with the latest changes, new features, fixes etc. Ensure to Star(*) the project on GitHub to get notified whenever the source code is updated.
Before we dive into building and running a fully featured Messenger for Android, ensure that you’ve read the following.
Building the code is as simple as:
Login using your phone number and OTP 123456. You can even start using the app you’ve just built to communicate with your family and friends.
Key SDKs user in this project
These apps use following Mesibo SDKs.
These apps also use following third party libraries/services.
Язык программирования Kotlin: от бэкенд до мобильного софта
Язык программирования, названный в честь острова в Финском заливе, быстро завоевал популярность. Окончательно он укрепил свои позиции после презентации Google I/O 2019. Востребованность Kotlin при разработке бэкенд-приложений и софта на платформе Android невозможно отрицать. Если вы решили изучить новый язык, но сомневаетесь с выбором, то вот пара доводов в пользу Kotlin.
Чем Kotlin понравился профессионалам
Молодой язык программирования, представленный российской компанией JetBrains в 2011 году, неспроста был признан Google приоритетным инструментом в мае 2019-го. Во-первых, код на Kotlin, если сравнивать с Java, занимает меньшее число строк. Во-вторых, язык напрямую поддерживается «корпорацией добра» — уже вышло несколько стабильных версий. В-третьих, Kotlin настолько лаконичен, что его код читается как текст на английском языке. Наконец, если у специалиста есть знания по Java-разработке, можно использовать в процессе все существующие фреймворки и библиотеки Java.
Курс Kotlin Backend Developer
Освоить перспективный инструмент программирования поможет онлайн-курс Kotlin Backend Developer, подготовленный образовательной платформой OTUS. Он рассчитан на 5 месяцев обучения — это по 4 академических часа в неделю. Начало занятий запланировано на 23 декабря. Вы освоите основы Kotlin и Kotlin Multiplatform, принципы разработки бэкенда, научитесь взаимодействовать с фреймворками, погрузитесь во все аспекты создания проекта вплоть до мониторинга готового продукта. Вы сможете стать слушателем программы, если имеете навыки работы на Linux и опыт программирования на любом языке ООП. Чтобы записаться на курс, нужно успешно выполнить вступительный тест.
Кстати, советуем посетить бесплатный вебинар, который поможет понять, как организовано обучение в OTUS. Он будет посвящён созданию современного микросервиса на Kotlin. Демоурок состоится 17 декабря в 19:00. Для получения доступа к занятию потребуется пройти тестирование. На вебинаре под руководством Вячеслава Лапина, профессионала с 12-летним опытом в IT, вы рассмотрите методологию компании Heroku, пионера в облачных решениях.
Курс Android Developer на Kotlin
Этот онлайн-курс рассчитан на профессиональное создание Android-приложений. Программа включает в себя углублённое изучение Android Architecture Components, тестирование мобильных утилит, RxJava, Dagger 2, многопоточности в Android, Koin, Material Design. Обучение начнётся 24 декабря и продлится 5 месяцев. Если у вас есть опыт в программировании, проверьте свой уровень подготовки до записи на курс, пройдя 15-минутный тест.
Перед обучением стоит посетить открытый урок 11 декабря в 20:00, посвящённый теме Unit-тестирования. На бесплатном вебинаре расскажут о модульной проверке и технологии TDD, научат тестировать компоненты, классы и методы в Java. Однако и данное мероприятие без успешного прохождения проверки знаний не посетить.
Как организован процесс обучения
Вебинары проходят в мессенджере Slack — там же взаимодействуют преподаватели и сокурсники. Раз в две недели вам придётся делать домашнее задание, рассчитанное на 3-4 часа свободного времени. При выполнении задач слушатели всегда могут получить обратную связь от менторов. Все лекции сохраняются в личном кабинете и доступны даже после обучения. Финальный месяц курса посвящён выполнению индивидуального проекта, который станет достойной частью вашего портфолио. Самые успешные выпускники получат приглашение на собеседование в партнёрские компании — OZON, «МТС», X5 Retail Group и многие другие.
How to build an Android messenger app with online presence using Kotlin
When building a chat application, it is essential to have an online presence feature. It is essential because your users will like to know when their friends are online, and are more likely to respond to their messages in real time.
In this article, we will be building a messenger app with online presence using Pusher Channels, Kotlin, and Node.js.
Here is a demo of what we will build:
Prerequisites
To follow along you need the following requirements:
Some familiarity with Android development is also required.
Building the backend server
Our server will be built using Node.js. To start, create a new project directory:
Next, create a new index.js file inside the project directory and paste the following code:
In the snippet above, we initialized Pusher, Express, and MongoDB. We are using Moongose to connect to our MongoDB instance.
Replace the PUSHER_APP_* keys with the ones on your Pusher dashboard.
Now let’s add our endpoints. The first endpoint we will add will be to log a user in. Paste the code below in your index.js file below the currentUser declaration:
This endpoint receives a username with the request, and either creates a new user or returns the data of the existing user.
Let’s add the next endpoint below the one above:
This second endpoint fetches all the users from the database and returns them.
Since we will be using a Pusher presence channel, we need an endpoint to authenticate the user. In the same file, paste this code below the endpoint above:
Since we are going to be using private channels, we need an endpoint for authentication. Add the following endpoint below the endpoint above:
After adding all the endpoints, install the necessary npm packages by running this command:
Before you run your application, make sure MongoDB is running already using this command:
Now you can run your application using the command below:
Your app will be available here: http://localhost:5000.
Building our Android application
Create your Android project. In the wizard, enter your project name — let’s say MessengerApp.
Next, enter your package name. You can use a minimum SDK of 19 then choose an Empty Activity.
Now that we have the project, let’s add the required dependencies for our app. Open your app module build.gradle file and add these:
Notably, we added the dependencies for Retrofit and Pusher. Retrofit is an HTTP client library used for network calls. We added the design library dependency too as we want to use some classes from it. Sync your gradle files to pull in the dependencies.
Next, let’s prepare our app to make network calls. Retrofit requires an interface to know the endpoints to be accessed.
Create a new interface named ApiService and paste this:
Here, we have declared three endpoints. They are for logging in, sending messages, and fetching users.
In some of our responses, we return Call el>. Let’s creat e the Use rModel. Create a new class c alled Use rModel and paste the following:
Above, we used a data class so that some other functions required for model classes such as toString and hashCode are added to the class by default.
We are expecting only the values for the id and name from the server. We added the online property so we can update later on.
Next, create a new class named RetrofitInstance and paste in the following code:
Finally, to request for the internet access permission update the AndroidManifest.xml file like so:
Now we can make requests using Retrofit.
The next feature we will implement is login. Open the already created LoginActivity layout file activity_login.xml file and paste this:
This layout contains an input field to take the username, and a button to make a login request.
Next, open the LoginActivity.Kt file and paste in this:
In the LoginActivity.Kt file, we set up a listener for our login button so that, when it is clicked, we can send the text to the server for authentication. We also stored the logged in user in a singleton class so that we can access the user’s details later.
Create a new class called Singleton and paste in this:
The layout contains a recycler view, which will give us all the lists of our contacts fetched from the database. Since we are displaying items in a list, we will need an adapter class to manage how items are inflated to the layout.
Create a new class named ContactRecyclerAdapter and paste in this:
This adapter has some overridden methods and some custom methods.
The onCreateViewHolder inflates how each row will look like. onBindViewHolder binds the data to each item by calling the bind method in the inner ViewHolder class. The getItemCount gives the size of the list.
For our custom methods, showUserOffline updates the user and shows when they are offline. While showUserOnline does the opposite. Finally, we have the add method, which adds a new contact to the list and refreshes it.
This layout is the visual representation of how each item on the layout will look like. The layout has an image view that shows the users online status. The layout also has a textview that shows the name of the contact beside the icon. The icons are vector drawables. Let’s create the files.
Create a new drawable named presence_icon_online and paste in this:
Create another drawable named presence_icon and paste in this:
Next, open the ContactListActivity class and paste in this:
In the same class, add the following methods:
Replace the PUSHER_APP_* keys with the values on your dashboard.
In the previous snippet, we used an extension function to transform the User object we receive from Pusher to our own UserModel object. Let’s define this extension.
Create a new class called Utils and paste this:
Now, since we referenced a ChatRoom activity earlier in the onUserClicked method, let’s create it.
The layout above contains a recycler view for the chat messages, an edit text to collect new messages, and a floating action button to send the message.
Next, create a new class called ChatRoomAdapter and paste in the following:
This adapter works in a similar fashion as the one we created earlier. One difference, though, is that the show online and offline methods are not needed here.
Next, create another class — named MessageMode — and paste in this:
The chat_item layout used in the onCreateViewHolder method of the adapter class represents how each layout will look like. Create a new layout called chat_item and paste in this:
Updating the ChatRoom class
Finally, open the ChatRoom activity class and paste in this:
In this file, we declared constants used to send data to the activity through intents. We also initialized variables we will use later, like the adapter and the contact details. We then called some additional methods in the onCreate method. Let’s add them to the ChatRoom class.
Add the fetchExtras method defined below to the class. The method gets the extras sent from the chatroom activity.
Replace the PUSHER_APP_* keys with the values on your dashboard.
The code above allows a user to subscribe to a private channel. A private channel requires authorization like the presence channel. However, it does not expose a callback that is triggered when other users subscribe.
The method above assigns a click listener to the floating action button to send the message to the server. After the message is sent, we clear the text view and hide the keyboard.
Add a method to the same class for hiding the keyboard like this:
That’s all for the application. Now you can run your application in Android Studio and you should see the application in action.
Make sure the Node.js API we built earlier is running before running the Android application.
Conclusion
In this article, you have been introduced to some Pusher capabilities such as the private and presence channel.
We learned how to authenticate our users for the various channels.
We used these channels to implement a private chat between two persons and an online notification for a contact.
The source code to the application built in this article is available on GitHub.
This post first appeared on the Pusher Blog.
If this article was helpful, tweet it.
Learn to code for free. freeCodeCamp’s open source curriculum has helped more than 40,000 people get jobs as developers. Get started
freeCodeCamp is a donor-supported tax-exempt 501(c)(3) nonprofit organization (United States Federal Tax Identification Number: 82-0779546)
Donations to freeCodeCamp go toward our education initiatives and help pay for servers, services, and staff.
Пишем комикс-приключение на Kotlin
Всем привет! Сегодня вас ждет легкая статья, которая расскажет как написать простую мобильную игру-викторину на Kotlin. Здесь я наглядно покажу как выглядит Kotlin для мобильной разработки и предложу свои идеи о том, как можно структурировать подобный проект. Что же, не буду томить вас графоманией, вперед!
Сейчас вы увидите остов идеи, которая ярко воспылала, но быстро прогорела. Мы с моим другом-дизайнером придумали сделать простую мобильную игру в текстовом формате. Жанр планировался приключенческий, а скупой текст должен был быть подогрет уникальным картинками в определенном стиле. К сожалению, дальше скелета приложения дело не продвинулось, поэтому я решил вынести его на публику. Вдруг кто-то найдет новые мысли. Сразу оговорюсь, вряд ли проект можно назвать серьезным решением, и для действительно больших приложений, возможно, стоит рассмотреть более сложные абстракции. Приложение стоит воспринимать как некий MVP.
Структура папок
Для начала поговорим о структуре папок. Вряд ли здесь будет что-то инновационное, но я считаю структуру папок в проекте одной из самых важных и интересных вещей в программировании.
Структура папок в приложении
В корне проекта лежит 2 Activity, которые у нас будут использоваться в приложении.
StartActivity отвечает за стартовый экран приложения, где можно начать игру и потенциально разместить какие-то глобальные элементы управления (настройки, кнопочки “поделиться” и т.п.).
MainActivity, которую корректнее было бы назвать как-то вроде GameActivity, будет отвечать за рендер вопросов викторины, вариантов ответов и соответствующих картинок.
Папка Entity содержит некоторые доменные сущности. Файл json с самим сюжетом игры, о котором я расскажу чуть позже, будет превращаться как раз в набор моделей из папки Entity.
Папка dao (от сокращения data access object) в проекте нужна для содержания сущностей, которые предоставляют доступ к данным. Именно здесь будут лежать классы, которые будут отвечать за хранение данных в Runtime, и классы, которые смогут превратить набор структурированных данных в объекты.
Папка core будет содержать объекты, которые относятся непосредственно к ходу игры. По итогу таких объектов вышло достаточно мало, однако здесь кроется потенциал для расширения.
Папка UI отвечает, как многие уже догадались, за какие-то интерфейсные сущности. В частности, сюда стоит помещать presenter-ы для наших activity.
Модель данных
В нашем MVP сами данные представляют собой json-файл, который содержит массив объектов. Вот пример одного из таких объектов:
Давайте разберем, что здесь для чего:
JSON файл с игрой содержится в папочке assests. Подразумевалось, что изначально данные игры будут храниться непосредственно в приложении. Однако, теоретически, мы можем получать этот JSON по сети, сохраняя его локально или в sqllite. Либо же мы можем организовать общение приложения по сети с некоторым сервером, сохраняя этот же протокол.
Тут же, в модели данных, можно прикрепить ссылки на картинки, если мы их хотели бы менять. Пока это логика не реализована, она лишь планировалась. Однако ассоциацию между картинкой и вопросом хранить лучше именно здесь.
Управление игрой и ее состоянием
Для начала, давайте разберемся как мы будем хранить модель данных в runtime. Для этого был придуман интерфейс Store.
Дальше мы создаем класс игры:
Класс содержит в себе 2 поля: экземпляр класса Store, о котором мы уже успели поговорить, и экземпляр текущего вопроса, на котором находится пользователь. Помимо этого, игра может закончится (когда type текущего вопрос F или S). Также в данном классе существует метод, который получит выбранный ответ и поменяет текущий вопрос на следующий.
Достаточно много логики уже содержится в модели данных. Например информация о том, закончилась ли игра, как она закончилась. При таком подходе нам остается просто отобразить информацию на экране.
Слегка неочевидный пункт содержится в модели вопроса (Question.kt). Давайте обратим внимание на реализацию геттера ответов:
Из этого метода мы всегда возвращаем List с 4 вариантами ответа, даже если вопрос предполагает, что их 2. Мы просто добиваем нашу коллекцию пустыми объектами с невалидными id. На слое представления они просто не будут отображены, это не изменит логику поведения экрана. Это небольшой костыль для того, чтобы нам было проще рендерить объекты.
Рендер игры
Тут все достаточно прозаично, мы просто отображаем вопрос и 4 варианта ответа, вешаем обработчики кликов на них и даем пользователю играть. При каждом выборе ответа мы обновляем страницу с текущим вопросом, отвечает у нас за это presenter:
Ну и когда игра закончена, мы возвращаем пользователя на StartActivity, передавая результат игры (текст текущего вопроса) в Intent:
Вместо заключения
Как я уже говорил, вряд ли это приложение можно назвать максимально production-ready. Здесь много допущений и мест, где срезаются углы. Это скорее MVP, скелет, который можно развить. Ниже я напишу то, что можно было бы улучшить или добавить:
Дизайн. Его тут вообще нет, есть пространство для маневра
Текущие UI-элементы неплохо отображаются на моем эмуляторе, однако на реальном смартфоне есть проблемы и конфликты с темой. Над этим можно поработать
Добавить различные картинки в модель данных, заменять картинки на экране
Добавить возможность сохранять данные из json в sqllite и работать с этим
Ну и ссылка на полные исходники для тех, кто хочет посмотреть на проект комплексно.
Telegraff: Kotlin DSL для Telegram
На Хабре тысячи статей про то, как сделать Телеграм-бота под разные языки программирования и платформы. Тема далеко не новая.
Но Telegraff – лучший фреймворк для реализации Телеграм ботов и я это под катом докажу.
Преамбула
В 2015 году российский рубль лихорадило. У меня были сбережения в долларах и я буквально каждые пять минут проверял курс, чтобы продать валюту по нужному мне курсу. Лихорадка затянулась, я устал и написал Телеграм бота (@TinkoffRatesBot), который оповещает, в случае достижения курса валют порогового (ожидаемого) значения.
Меня очень тронула эта задача. Бота написал довольно быстро, но только вот удовлетворения не получил.
В интеграции с Телеграм нет и не было никаких проблем. Этот вопрос решается за пару часов. И я даже удивлён, что есть целые библиотеки на Java (субъективно, с отвратительным по качеству кодом) по интеграции с Телеграм, заработавшие больше тысячи звезд на Github.
Основным вызовом для меня стала система сценариев: пользователь вызывает команду, например, «/taxi», бот задаёт ему ряд вопросов, каждый ответ валидируется и может влиять на порядок последующих вопросов, формируется привычная «форма», отдаётся в конечный метод на обработку для формирования ответа.
Я сделал это, но структура классов, уровни абстракции, все это было так неоднородно, что на это было горько смотреть. Меня мучал вопрос: Как это лаконично и органично перенести в объектно-ориентированную модель?
Хотелось иметь что-то простое, удобное, а самое главное — иметь возможность описать весь сценарий в одном изолированном файле, чтобы не нужно было просматривать половину проекта, чтобы понять цепочку взаимодействия с пользователем.
Не сказать, что вопрос стоял очень остро, потому что задача была уже решена. Скорее, иногда я подумывал о нем. В мыслях был Groovy DSL, но когда появился Kotlin, выбор стал очевиден. Так появился Telegraff.
Да, конечно, не было никакого соревнования, в котором бы победил Telegraff. И утверждения о том, что Telegraff – лучший, не нужно воспринимать буквально. Но Telegraff – новый, уникальный подход в рамках этой задачи. Легко быть лучшим, будучи единственным.
Как этим пользоваться?
Зависимости
Первым делом нужно указать дополнительный репозиторий для зависимостей. Возможно, на определенном этапе я опубликую Telegraff в Maven Central или в JCenter, но пока так.
Осталось дело за малым. Для использования Telegraff нужно указать лишь одну зависимость spring-boot-starter:
Конфигурация
Конфигурация проекта проста и может ограничиваться первыми двумя-тремя параметрами:
Пора писать сценарии!
Обработчики
Обработчики (сценарии) – ключевая часть Telegraff. Именно здесь задается цепочка взаимодействия с пользователем. Суть в том, что каждая команда, вроде «/start», «/taxi», «/help» – это отдельный сценарий/скрипт/обработчик/handler.
Сценарий может содержать набор шагов (вопросов), необходимых пройти пользователю, для того, чтобы выполнить команду. Другими словами, пользователь должен заполнить форму. И так, как из интерфейса – мессенджер, надо с пользователем разговаривать, спрашивать.
Надо ли объяснять, что ответы пользователя нужно валидировать? Первым делом пользователь то и сделает, что ответит не так, как вы ожидаете.
Ну и в конце концов, сценарий может ветвиться, т.е. каждый ответ на вопрос может влиять на порядок последующих.
Ключи степов нарочито небыли вынесены в константы. В продакшене, конечно, такого лучше избегать.
Обработчик может и не иметь шагов вовсе. В таком случае, нужно определить лишь поведение обработчика на вызов команды.
Пробуем
Вообще telegraff-sample – нарочито независимый проект, который не связан с родительским и имеет даже собственный Gradle Wrapper. Можно оставить только эту папку. Это своего рода архетип.
Как это устроено?
Telegram
Каждый метод был нарочито реализован индивидуально в силу ряда обстоятельств: начиная от того, что используется спринговский RestTemplate (и тесты под него), заканчивая специфичностью API от Telegram.
Как можно было заметить из конфигурации, в Telegraff существуют два типа клиентов этого API: PollingClient, WebhookClient. В зависимости от конфигурации, будет объявлен тот или иной бин.
И хотя методы получения обновлений (новых сообщений) от Telegram отличаются, суть неизменна и сводится к одному – публикации события ( TelegramUpdateEvent ) о новом сообщений через спринговский EventPublisher (паттерн «Наблюдатель»). При желании можно реализовать собственного слушателя, подписавшись на этот тип событий. Логичный, как мне кажется, слой абстракции, ведь абсолютно не имеет значения каким именно образом было получено сообщение.
Фильтры
Как только было получено новое сообщение, требуется его обработать и ответить пользователю. Для этого сообщению нужно пройти через цепочку фильтров.
Это похоже на привычные для Java программистов фильтры из Java EE. Разница лишь в том, что так называемые Обработчики (если проводить параллель с Java EE, то это Сервлеты) не являются независимыми от фильтров, а являются их частью.
Итак, фильтры упорядочены и могут пускать сообщения дальше по цепочке, могут нет.
HandlersFilter – основной фильтр в текущем процессе. Именно этот фильтр хранит состояния пользовательских чатов, находит и вызывает нужный обработчик (сценарий), применяет блоки валидации, определяет порядок шагов и отвечает пользователю.
Обработчики
Система сценариев (обработчики) Telegraff построена на Kotlin DSL. Если очень вкратце, то это про лямбды и про билдеры.
Отдельно обозревать Kotlin DSL смысла не вижу, т.к. это совсем другой разговор. Есть замечательная документация от JetBrains и исчерпывающий доклад от i_osipov.
Нюансы
Этот раздел посвящен присутствующим особенностям. Все они, на мой взгляд, не являются критичными, некоторые из них можно исправить, некоторые нет. Но об этих аспектах необходимо знать.
Если у вас есть желание участвовать или знание того, как поправить тот или иной пункт из этого раздела, буду очень благодарен.
Telegram
Вероятно, слой интеграции с Telegram описан не полностью. Реализованы лишь те методы, которые мне были нужны. Если есть чего-то, чего вам лично не хватает, поправьте TelegramApi и засылайте PR!
Из важных частей на текущий момент – отсутствие поддержки inline-клавиатуры (это когда клавиатура прям под сообщением в ленте). Задача отягощена тем, что inline-клавиатуры нужно правильно «вписать» в действующую структуру так, чтобы это оставалось просто, удобно, изолированно. Уже есть хорошая идея по реализации этого функционала, но она еще ни в каком виде не реализована и не опробована.
Fat JAR
Для того, чтобы эту проблему решить, можно распаковывать зависимости в runtime. То есть, когда приложение запускается, JARка зависимости из основного пакета разворачивается где-нибудь на диске и до нее указывается classpath. Сделать это довольно просто через конфигурацию bootJar :
Однако, для того, чтобы ссылаться из обработчиков (скриптов) к вашим бинам (сервисам, например), они тоже должны быть распакованы. Что, в принципе, нивелирует пользу такого подхода.
Обо всем этом я довольно детально писал здесь.
Порядок инициализации
Здесь хотелось бы отметить два обстоятельства.
Во-вторых, нужно помнить, что ваши скрипты могут быть проинициализированы раньше, чем все ваше приложение и бины. Если положить, например, ссылку на контекст в статическую переменную и первой же строкой в файле скрипта попытаться достать какой-нибудь сервис, может статься, что его не будет у контекста, т.к. он еще не был проинициализирован. Для того, чтобы на такие проблемы не натыкаться, воспользуйтесь этим методом Telegraff. Он гарантирует, что контекст будет проинициализирован и все нужные бины будут доступны. Пример можно посмотреть здесь.
Заключение
Захотелось попробовать — форкай,
Захотелось поправить — отправляй PR,
Захотелось отблагодарить — поставь звездочку в Github, лайкни пост и расскажи друзьям!