Добро пожаловать на восьмой урок курса для начинающих разработчиков под названием “Как гуглить?”.
Если вы смогли добраться до этого урока – значит вам уже более чем достаточно знаний для разработки собственных мобильных приложений.
Сегодня мы с вами разберем кроссплатформенные мобильные приложения. По большому счету – это веб-сайты, завёрнутые в мобильные приложения, при этом такие приложения без труда могут использовать возможности мобильного устройства, такие как – доступ к камере, push-уведомления, deeplinking, bluetooth и т.д.
Перво-наперво, нам необходимо скачать и установить платформу NodeJS, которая позволит превратить язык Javascript из узкоспециализированного языка в язык общего назначения.
В этом уроке мы будем разрабатывать приложение, в первую очередь, для Android, поэтому нам также потребуется Android Studio. Если вы хотите скомпилировать приложение для iOS – вместо Android Studio вам потребуется Xcode. Также, для сборки Android-приложения нам потребуется Java SE Development Kit.
Далее, я рекомендую бегло ознакомиться с документацией к Apache Cordova – программной платформе, позволяющей разрабатывать мобильные приложения при помощи Javascript.
Перейдем сразу к делу – после установки NodeJS, открываем командную строку NodeJS и устанавливаем Apache Cordova через менеджер репозиториев npm (идущий в комплекте с NodeJS). Для этого в командной строке NodeJS напишем следующую команду:
npm install -g cordova
Сегодня мы разработаем небольшое мобильное приложения для надёжного хранения ваших паролей (или другой конфиденциальной информации), с возможностью доступа на разных устройствах.
Создаем новое приложение, для этого в командной строке NodeJS напишем следующее:
cordova create passapp com.example.passapp PassApp
Здесь
- passapp – директория разрабатываемого приложения на вашем ПК
- PassApp – имя вашего приложения
- com.example.passapp – домен вашего приложения.
Apache Cordova создаст новую директорию (passapp) со всеми необходимыми файлами. Перейдем в эту директорию в командной строке:
cd passapp
Добавим платформу для нашего приложения:
cordova platform add android
Теперь выведем перечень используемых платформ.
cordova platform ls
Нас будет интересовать установленная версия платформы
Переходим в Google и формируем следующий поисковый запрос «apache cordova android 10.1.2 api level» (вместо «10.1.2» укажите вашу версию платформы).
Нам необходимо определить подходящую версию Android SDK для используемой платформы Apache Cordova. В случае с версией платформы 10.1.2 необходимый API Level будет 30.
Открываем Adnroid Studio, переходим на вкладку Customize, нажимаем All settings. В появившемся окне находим: Apperiance & Behavior -> System Settings -> Android SDK. Нажимаем 2 галочки внизу: “Hide Obsolete Packages” и “Show Package Details”.
Выбираем на вкладке “SDK Platforms” – Android SDK Platform 30, а на вкладке “SDK Tools” – 30.0.3 и нажимаем “Apply”
Теперь нам потребуется установить Gradle скачиваем дистрибутив (complete) из последнего релиза и куда-нибудь его распаковываем.
Теперь нам осталось настроить системные пути, если вы используете Windows. Правой кнопкой мыши кликаем по “Мой компьютер” и нажимаем “Свойства”, в открывшемся окне выбираем “Дополнительные параметры системы”, а там – “Переменные среды”. В разделе “Системные переменные”, если переменная “ANDROID_HOME” еще не была создана – нужно её создать, а в качестве значения переменной – указать следующее:
C:\Users\USER\AppData\Local\Android\Sdk;C:\Users\USER\AppData\Local\Android\Sdk\platform-tools
где USER – имя вашего пользователя в операционной системе.
Также, убедимся, что в системной переменной “Path”, есть следующие пути:
- к директории “bin” для Gradle, куда мы его распаковали
C:\Program Files\Android\Gradle\bin - к директории “platform-tools” для Android Studio
C:\Users\USER\AppData\Local\Android\Sdk\platform-tools
Если их нет – добавим и сохраним изменения.
Чтобы изменения применились – перезагружаем компьютер.
Для того, чтобы собрать готовое приложение в установочный файл для телефона, воспользуемся командой build.
После перезагрузки компьютера – снова открываем командную строку NodeJS и пишем следующее:
cd /
cd passapp
cordova build
Если нужно собрать приложение только для какой-то конкретной платформы – можем указать это для команды build
cordova build android
Готовые приложения будут размещаться в директории platforms/название платформы/output
Попробуем собрать наше первое приложение, перенести его на телефон и установить.
Отлично! Это всё, что нужно нам знать об Apache Cordova для того, чтобы продолжить разработку нашего мобильного приложения.
Теперь, скачаем директорию assets, в которой хранятся файлы фреймворка Bootstrap, из панели управления хостингом для нашего сайта, который мы разрабатывали на прошлых уроках – нам она потребуется, чтобы подготовить простенький интерфейс для нашего приложения. Разместим папку assets в папке www нашего мобильного приложения. А также скопируем в папку www нашего приложения файл библиотеки jQuery.
Теперь найдем файл index.html в папке www нашего мобильного приложения и откроем его в текстовом редакторе. По большему счету, единственное, что должно остаться здесь – это подключение библиотеки Cordova – удалим весь код, кроме этого скрипта.
Теперь скопируем в index.html код нашего сайта, сохранив скрипт Cordova. Обратите внимание, что, по большему счету, Apache Cordova – это браузер, который не сможет распознать PHP-код. Поэтому, шапку и подвал, которые мы выносили в отдельные файлы на хостинге нужно разместить вместо PHP-функций.
Удалим всё лишнее и оставим в DOM-дереве только контейнер. Удалим лишние стили, а также, для удобства разработки в браузере – заменим пути к стилям и скриптам на относительные (уберем символ “/” в их адресах).
Теперь перейдём к нашему хостингу и подготовим серверную часть для нашего приложения. Переходим к веб-интерфейсу управления базой данных и создаем новую таблицу users, состоящую из следующих столбцов:
- id (int, primary key) – идентификатор пользователя
- login (varchar, 64) – логин пользователя
- password (varchar, 64) – хеш пароля
- data (text) – набор паролей или прочая конфиденциальная информация пользователя
Сразу же создадим нашего первого пользователя. В ячейке password выберем MD5, что позволит хранить нам только хеш пароля, а не весь пароль в открытом виде.
Далее, создадим таблицу sessions, в которой мы будем хранить информацию о токенах, которыми пользователи приложения могут подписывать свои запросы:
- id (int, primary key)
- date (timestamp, current timestamp)
- user (int)
- token (varchar, 16)
Теперь создадим в корневой директории с файлами сайта папку passwords – там мы будем хранить API для нашего сервиса. Сразу же создадим в папке passwords файл auth.php и разместим в нём следующий код:
real_escape_string($_POST['login']);
$password = md5($_POST['password']);
$counter = 0;
$sql = "SELECT * FROM `users` WHERE `login` = '$login'";
if ($result = $mysqli -> query($sql)){
foreach($result as $row){
$counter++;
$user_id = $row['id'];
$db_password = $row['password'];
}
}
if ($counter != 1){
$response['status'] = "error";
$response['text'] = "Пользователь не найден";
echo json_encode($response);
$mysqli -> close();
exit;
}
if ($password != $db_password){
$response['status'] = "error";
$response['text'] = "Не правильный пароль";
echo json_encode($response);
$mysqli -> close();
exit;
}
$token = generateRandomString();
$sql = "INSERT INTO `sessions` (user, token) VALUES ($user_id, '$token')";
$mysqli -> query($sql);
$response['status'] = "ok";
$response['text'] = $token;
echo json_encode($response);
$mysqli -> close();
?>
Давайте разберемся, что здесь написано.
В самом начале мы задаем заголовок Access-Control-Allow-Origin, который позволит принимать запросы из любых доменов.
Далее мы создаем функцию, которая позволит генерировать случайную строку – она нам понадобится для генерации токена, по которому в дальнейшем мы будем распознавать пользователя.
Далее мы проверяем, чтобы в API были отправлены и логин, и пароль. В противном случае – сообщаем об ошибке.
После этого, мы поднимаем подключение к базе данных. Далее мы экранируем переданный логин и сохраняем его в переменную $login. А также, создаем MD5-хеш для пароля, чтобы провести сверку с информацией о пароле в БД.
Ищем в таблице пользователей, полученный логин, сохраняем в переменную $user_id – идентификатор пользователя с этим логином, а в переменную $db_password – MD5-хеш пароля, который хранится в базе данных. С помощью переменной $counter считаем сколько пользователей нашлось в базе данных по заданному логину. Если число пользователей не равно 1 (т.е. каким-то образом в БД попало 2 одинаковых логина, или, наоборот, пользователей по данному логину не найдено) – прерываем выполнение скрипта с ошибкой.
Далее, сверяем MD5-хеш от переданного в API пароля с информацией, которая хранится в БД.
Если все проверки были пройдены успешно – создаем новый токен и сохраняем его в таблицу sessions вместе с идентификатором пользователя.
Результат выполнения скрипта, вне зависимости от того был ли он выполнен успешно или завершился с ошибкой – записываем в массив, а сам массив перед тем как отдать ответ преобразуем в JSON-строку. Такой подход окажется полезным для удобного отображения ошибок в нашем приложении.
Теперь мы создадим еще один API-метод, который позволит нам получить конфиденциальную информацию по запросу пользователя в приложении. Создаем в директории passwords файл get.php и разместим в нем следующий код:
real_escape_string($_POST['token']);
$counter = 0;
$sql = "SELECT * FROM `sessions` WHERE `token` = '$token'";
if ($result = $mysqli -> query($sql)){
foreach($result as $row){
$counter++;
$user_id = $row['user'];
}
}
if ($counter != 1){
$response['status'] = "error";
$response['text'] = "Токен не найден";
echo json_encode($response);
$mysqli -> close();
exit;
}
$counter = 0;
$sql = "SELECT * FROM `users` WHERE `id` = '$user_id'";
if ($result = $mysqli -> query($sql)){
foreach($result as $row){
$counter++;
$output = $row['data'];
}
}
if ($counter != 1){
$response['status'] = "error";
$response['text'] = "Пользователь не найден";
echo json_encode($response);
$mysqli -> close();
exit;
}
$response['status'] = "ok";
$response['text'] = $output;
echo json_encode($response);
$mysqli -> close();
?>
Этот API-метод позволит получить конфиденциальную информацию пользователя.
Создадим еще один API-метод, позволяющий обновить конфиденциальную информацию пользователя в базе данных. Создадим для этого файл update.php
real_escape_string($_POST['token']);
$data = $mysqli -> real_escape_string($_POST['data']);
$counter = 0;
$sql = "SELECT * FROM `sessions` WHERE `token` = '$token'";
if ($result = $mysqli -> query($sql)){
foreach($result as $row){
$counter++;
$user_id = $row['user'];
}
}
if ($counter != 1){
$response['status'] = "error";
$response['text'] = "Токен не найден";
echo json_encode($response);
$mysqli -> close();
exit;
}
$counter = 0;
$sql = "SELECT * FROM `users` WHERE `id` = '$user_id'";
if ($result = $mysqli -> query($sql)){
foreach($result as $row){
$counter++;
}
}
if ($counter != 1){
$response['status'] = "error";
$response['text'] = "Пользователь не найден";
echo json_encode($response);
$mysqli -> close();
exit;
}
$sql = "UPDATE `users` SET `data` = '$data' WHERE `id` = $user_id";
$mysqli -> query($sql);
$response['status'] = "ok";
echo json_encode($response);
$mysqli -> close();
?>
Теперь, возвращаемся к нашему мобильному приложению и открываем файл www/index.html в текстовом редакторе.
Перво-наперво, нам необходимо авторизовать пользователя, поэтому добавляем в наше приложение HTML-форму для авторизации:
По мимо логина и пароля, как вы видите, в форме появился некий “Ключ”. Он нам понадобится, чтобы не хранить конфиденциальную информацию в открытом виде в базе данных. Когда пользователь решит обновить информацию в приложении – она будет зашифрована на стороне устройства пользователя при помощи этого ключа, и в базе данных информация будет хранится в зашифрованном виде. Точно также, для того, чтобы расшифровать информацию и базы данных – пользователю потребуется специальный ключ, который он придумает сам и будет знать только он.
Теперь, добавим в наше мобильное приложение Javascript-код, который будет отвечать за авторизацию пользователя:
$("#auth").submit(function(e){
e.preventDefault();
var login = $("#login").val();
var password = $("#password").val();
var user_key = $("#key").val();
$.ajax({
method: "POST",
url: "https://илонмаск.рф/passwords/auth.php",
data: {
login: login,
password: password
}
}).done(function(response) {
var json_data = jQuery.parseJSON(response);
if (json_data.status == "ok"){
localStorage.setItem('token', json_data.text);
localStorage.setItem('key', user_key);
} else {
alert(json_data.text);
}
});
});
Этот скрипт позволит при отправке формы совершить запрос с API и в случае успеха – получить токен. Секретный ключ пользователя в API не передается. Токен для API и секретный ключ сохраняются в локальное хранилище устройства для того, чтобы при дальнейшем использовании не проходить заново процедуру авторизации.
В случае же, если API вернёт ошибку – мы покажем в приложении всплывающее окно с ошибкой.
Теперь, добавим в наше приложение textarea, в которой мы будем хранить конфиденциальную информацию, а также кнопку для сохранения изменений:
Теперь создадим функцию, которая позволит получить конфиденциальную информацию пользователя в разместить её в textarea.
function load_data(){
$.ajax({
method: "POST",
url: "https://илонмаск.рф/passwords/get.php",
data: {
token: localStorage.getItem('token')
}
}).done(function(response) {
var json_data = jQuery.parseJSON(response);
if (json_data.status == "ok"){
$("#user_data").val(CryptoJS.AES.decrypt(json_data.text, localStorage.getItem('key')).toString(CryptoJS.enc.Utf8));
$("#auth").css('display', 'none');
$("#private").css('display', 'block');
} else {
alert(json_data.text);
localStorage.removeItem('key');
localStorage.removeItem('token');
$("#auth").css('display', 'block');
$("#private").css('display', 'none');
}
});
}
Добавим нашу функцию load_data в предыдущую конструкцию, в случае, если пользователь был успешно авторизован – это позволит скрыть форму авторизации и показать textarea с пользовательской информацией.
Также, добавим проверку на наличие токена и секрета при запуске приложения, что позволит показать пользовательскую информацию сразу после запуска мобильного приложения, в случае, если пользователь ранее уже был авторизован.
$(document).ready(function() {
if ((localStorage.getItem('token') !== null) && (localStorage.getItem('key') !== null)){
load_data();
} else {
localStorage.removeItem('key');
localStorage.removeItem('token');
}
});
Теперь добавим обработчик для кнопки сохранения изменений
$("#save").click(function(e) {
e.preventDefault();
$.ajax({
method: "POST",
url: "https://илонмаск.рф/passwords/update.php",
data: {
token: localStorage.getItem('token'),
data: CryptoJS.AES.encrypt($("#user_data").val(), localStorage.getItem('key')).toString()
}
}).done(function(response) {
var json_data = jQuery.parseJSON(response);
if (json_data.status == "ok"){
alert ('Информация успешно обновлена')
} else {
alert(json_data.text);
}
});
});
А теперь – самое интересное. Мы добавим в наш сервис шифрование на стороне пользователя при помощи библиотеки CryptoJS. Для этого подключим CryptoJS с помощью следующего кода:
Теперь, добавим расшифровку в нашу функцию load_data с помощью следующей конструкции:
CryptoJS.AES.decrypt(json_data.text, localStorage.getItem('key')).toString(CryptoJS.enc.Utf8)
А конфиденциальную информацию будем отправлять в API после обработки при помощи следующей конструкции:
CryptoJS.AES.encrypt($("#user_data").html(), localStorage.getItem('key')).toString()
Итого, после всех изменений мы должны получить следующий код в файле index.html нашего мобильного приложения:
Теперь нам осталось только собрать наше приложение и протестировать на смартфоне. Возвращаемся в командную строку NodeJS и собираем приложение
cordova build
Скачать исходные файлы урока №8