Русский
Русский
English
Статистика
Реклама

Google play

Дайджест интересных материалов для мобильного разработчика 364 (27 сентября 4 октября)

04.10.2020 14:17:49 | Автор: admin
В этом дайджесте обновления Android, собственный движок для игр, симуляция волос и создание VHS-эффектов, No-Code платформы машинного обучения и доходы приложений. Приятного чтения!


У меня был простой рендер спрайтов и текста, простая система обработки ввода, из которой можно было получать информацию о мышке и нажатых клавишах, и всякие утилиты-обвязки вспомогательных систем движка. В общем какую-то простую картинку вывести я мог. В последствии это все очень сильно изменилось и поросло архитектурными хитростями. Начиная с Android 8 (у некоторых вендоров с 7.1) в системе появился новый механизм накатки OTA-обновлений, т. н. Seamless A/B OTA Updates бесшовные обновления. В этом посте я опишу общие принципы его работы, рассмотрю механизм с точки зрения разработчика, а также проведу сравнение со старым (будем его называть recovery-based) подходом применения обновлений.

Этот дайджест доступен в виде еженедельной рассылки. А ежедневно новости мы рассылаем в Telegram-канале.

iOS

(+22) Navigation bar и анимация перехода
Apple запустила генератор коротких ссылок и QR-кодов для App Store
Apple отказалась от 30% налога ради малого бизнеса
Использование AVAudioEngine для записи, сжатия и потоковой передачи звука на iOS
SKOverlay в SwiftUI
Core Data и SwiftUI 2.0
Используем кастомные Debug Descriptions, чтобы упростить отладку Swift
10 запутанных, но важных функций Swift
2 способа исполнения MVVM iOS
SwiftUI и Firestore: обновление данных
Как сделать раздвигающийся TableView с помощью Swift
Instructions: пояснения и обучение работе с продуктом
Tiktok Clone: короткие видео на Swift и Firebase
Twitter Text: парсинг текста

Android

(+8) Как разработать аналог Zoom для ТВ-приставок на RDK и Linux. Разбираемся с фреймворком GStreamer
(+7) Холодный запуск Android-приложения
(+6) Еще раз про многомодульность Android-приложений
(+6) Как устроен Push Kit от Huawei
(+4) Как спроектировать пошаговое заполнение данных в мобильном приложении
(+4) Google Play In-App Review API: пошаговое руководство по внедрению
(+1) Голос в мобильном приложении: учимся вызывать экраны и заполнять формы без рук
Google упростит работу со сторонними магазинами в Android 12
Google Play будет тщательнее следить за оплатой покупок в приложениях
Беспроводная Android-разработка с локальным устройством
Асинхронные сообщения с Kotlin и RabbitMQ
Первые мысли о Jetpack Compose
Изменение стартовых шаблонов Android
Splash Screen в Android
Время плыть: переход с Kotlin на Flutter
Исследуем Kotlin DSL
Развенчиваем мифы о производительности Android
Создание тепловых карт с помощью Google Maps для Android
Все, что вам нужно знать о биометрической библиотеке Android
JetMessenger: клон Facebook Messenger на Jetpack Compose
CircleMenu: круговое меню для Android

Разработка

(+22) Plague M.D. Я остался в России и меня поглотила Чума. Сопли и нытье прогера
(+16) Выводы, которые я сделал, помогая стартапу для секс-чатов повысить конверсию
(+8) InheritedWidget во Flutter
(+8) Симуляция волос и тканей с Unity Cloth на мобильных устройствах
(+6) Создание эффекта VHS-видео в Unreal Engine
(+6) Flutter клёвенький у меня только такое объяснение. Обзор лучших выпусков Flutter Dev Podcast
(+6) Как создать мини-приложение: база знаний VK Mini Apps
Podlodka #183: обратная связь
Финал фестиваля программирования RuCode
GitHub запускает сканирование кода на уязвимости
Как изменить жизнь программиста с правилом 80/20
Курсы Как создавать мобильные приложения и игры в Humble Bundle
4 расширения VS Code для того, чтобы расслабиться на работе
Интервью с product-менеджером Flutter и Dart (Google)
Facebook против Google: битва межплатформенных фреймворков
Лучшие практики CI/CD
GitHub Codespaces: работа с Flutter
Лучший совет по созданию программного обеспечения от моего ментора
Четыре вещи, которые нужно забыть, чтобы стать лучшим программистом
Мои первые 24 часа с Flutter
7 способов действительно чему-то научиться из туториалов

Аналитика, маркетинг и монетизация

(+25) Как приложения без возможности выигрыша вытягивают у пользователей миллионы долларов
(+3) История Waze: от бессмыслицы до миллиардной компании
(+1) Разбор игры RAID: Shadow Legends (монетизация через поведенческую психологию)
(0) Локализационное тестирование: зачем оно нужно приложению или сайту?
Сингл группы BLACKPINK Lovesick girls выходит в PUBG MOBILE
IronSource открывает доступ к in-app bidding платформе для всех
make sense: О выходе на зарубежный рынок
Доходы приложений в 3 квартале выросли на 32% до $29 млрд.
Epic и Apple отказались от суда присяжных
В России вступил в силу Закон о блокировке пиратских приложений
Почему инфлюэнсеры-звезды, такие как Ли Цзяци, так важны для бизнеса, нацеливающегося на Китай
Rephrase.ai: генерация людей для рекламы
Как мы запустили приложение для анимации фото на Product Hunt
Запуск инди-приложения

AI, Устройства, IoT

(+27) Лучшие IDE для Raspberry Pi
(+17) Знакомство с Node-RED и потоковое программирование в Yandex IoT Core
(+12) Добавляем в плеер функцию Ambilight при помощи умных ламп Xiaomi
(+1) NB-IoT. Non-IP Data Delivery или просто NIDD. Тестирование с коммерческим сервисом МТС
(0) Умный дом в каждую квартиру многоквартирного дома. Детально о контроллере и шлюзах
8 No-Code платформ машинного обучения для мобильных разработчиков
Продажи Apple Watch 6 вдвое опережают продажи предыдущей версии

Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку пришлите, пожалуйста, в почту.
Подробнее..

Как написать простое Android ToDo-приложение на Java

15.03.2021 22:22:10 | Автор: admin

Предисловие

Я не являюсь профессиональным разработчиком с огромным стажем в данной области (и это даже не хобби, а лишь нужда в разработке конкретного приложения), потому данная статья, полагаю, будет полезна новичкам, таким же, как и я был в начале разработке своего приложения. Возможно, кто-то найдет что-то полезное из данной статьи, какие-то кусочки окажутся частью ваших будущих разработок.

Я расскажу вам как написать простенькое ToDo-приложение на Android с тремя активностями (рабочими экранами).

Ссылка на проект на Github будет в конце данной статьи.

Установка и первичная настройка

Для разработки приложения я рассмотрю использование бесплатной IDEIntellij от разработчиков JetBrains - Android Studio, у меня версия 4.1.1.

После успешной установки IDE и запуска нажимаем на самую первую кнопкуStart a new Android Studio Project. Далее появится мастер первичной подготовки проекта:

  • выберем подходящий шаблон, в моем случае это Empty Activity - он самый простой для новичков, так как при первом запуске будет всего 1 XML файл с версткой и один java файл MainActivity.

  • На следующем экране придумываем имя приложению; помните, что package name, после публикации на Google Play изменить нельзя (иначе Google Play посчитает это другим приложением (поправьте меня, если я ошибаюсь). Выбираем язык Java, так как по нему данная статья, а также, по нему больше информации в Интернете, чем по Kotlin.

  • Минимальный SDK выбираем под Android 5.0, так как данного API будет предостаточно для наших задач, заодно мы получим большой охват, в том числе старых устройств: планшеты, смартфоны, встроенные системы.

Скриншоты: установка и первичная настройка

Далее раскрываем вкладку Project и находим в каталоге Java><Ваш_Проект> файл MainActivity.java, в котором мы будем описывать все происходящее на главном экране.

Подготовка макетов (layouts) - внешний облик приложения

После рассмотрим файл MainActivity.xml, для этого нам нужно найти каталог res>layout>. Откроем MainActivity.xml для создания облика первой - главной страницы и перетягивая спанели Palette необходимые нам типы объектов.

Советую вам размещать объекты под ConstraintLayout, так объекты можно будет привязывать узелками к родительскому ConstraintLayout, который по умолчанию занимает всю пространство, а после привязки узелков, мы можем размещать объекты на нужном нам вертикальном и горизонтальном выравнивании.

Кстати, вместо px, тут используется другая величина - dp, позволяющая на разных экранах видеть одинаковый и желаемый результат.

Кстати, также, советую названия Текст полей переназначать в String значения, чтобы в дальнейшем было проще делать перевод интерфейса - подобный функционал уже встроен в Android Studio. Для этого нажимаем на объект, далее в меню Свойств объекта находим поле text и нажимаем на маленькую плашку-кнопку справа от текста. В открывшимся окне, нажимаем на плюсик слева сверху и создаем название String-переменной и ее значение по умолчанию:

Создание String-переменнойСоздание String-переменной

Для перевода интерфейса, необходимо сохранить изменения и над нашим конструктором Layout нажать на кнопку Default (en-us) и выбрать Edit Translations, далее найти слева сверху значок глобуса и нажать на него для добавления нового языка:

Переводы для интерфейсовПереводы для интерфейсов

Таким образом создадим дополнительные макеты (layouts) для оставшихся двух окон:

Скриншоты: еще два макета
Макет Activity_Settings.xmlМакет Activity_Settings.xmlМакет Activity_Advanced.xmlМакет Activity_Advanced.xml

Программируем на Java под Android

Еще раз повторюсь, что это Tutorial больше для новичков; дальше я буду комментировать практически каждую строчку. Ссылка на проект на Github будет в конце данной статьи.

Открываем файл Main_Activity.java, который будет отвечать за логику наших переключателей и главного экрана в целом, а она такова:

  • В самом верху должен отображаться пользовательский заголовок, если он настроен.

  • На переключателях должен отображаться тот текст, который пользователь настраивает из окна с макетом Activity_Settings.xml

  • Количество переключателей должно соответствовать заданному числу из окна макета Activity_Advanced.xml

  • После выхода из приложения и повторного запуска все переключатели должны оставаться в том же положении, в котором пользователь их оставил

  • Сброс переключателей возможен только, если переключатель Уверен/-а? включен.

  • А также, должны работать оставшиеся кнопки меню.


    Пишем следующее:

Код под спойлером: 156 строчек
package com.bb.myapplication;import androidx.appcompat.app.AppCompatActivity;import androidx.appcompat.widget.SwitchCompat;import android.content.Intent;import android.content.SharedPreferences;import android.graphics.Color;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    //Создаем 9 переключателей с помощью массива    SwitchCompat[] switcharray = new SwitchCompat[9];    Boolean Reset; //Булев для выключения переключателя    Button NextButton;    public int[] list_of_switches = {            R.id.switch_compat1,            R.id.switch_compat2,            R.id.switch_compat3,            R.id.switch_compat4,            R.id.switch_compat5,            R.id.switch_compat6,            R.id.switch_compat7,              R.id.switch_compat8,             R.id.switch_compat10, //переключатель "Вы уверены?" //8    };    //Нажатие кнопки Сброс    public void ResetButtonClick (View view) throws IllegalAccessException {        Reset =false;        if (switcharray[8].isChecked()) { //Если переключатель "Вы уверены?" нажат, то разрешаем переключить в false остальные переключатели            SharedPreferences.Editor editor = getSharedPreferences("save"                    ,MODE_PRIVATE).edit();            //Сохраняем в Intent значения всех переключателей в False            for (int k=0; k<10; k++) {                editor.putBoolean("value"+k, false);            }            editor.apply();            //Устанавливаем все переключатели в значение False            for (int i=0;i<9;i++){                switcharray[i].setChecked(false);            }            //Reset background color of checked SwitchCompats            for (int i = 0; i < 9; i++) {                findViewById(list_of_switches[i]).setBackgroundColor(Color.TRANSPARENT);            }        }    }    //Создание формы / открытие приложения    @Override    protected void onCreate(final Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        //Назначаем полям значения по умолчанию и сохраняем их в Intent        String[] tsfield = new String[8];        SharedPreferences prefs = getSharedPreferences("MY_DATA", MODE_PRIVATE);        tsfield[0] = prefs.getString("KEY_F0", "Выключил газ");        tsfield[1] = prefs.getString("KEY_F1", "Выключил воду");        tsfield[2] = prefs.getString("KEY_F2", "Покормил кошек");        tsfield[3] = prefs.getString("KEY_F3", "Закрыл окна");        tsfield[4] = prefs.getString("KEY_F4", "Выключил Интернет");        tsfield[5] = prefs.getString("KEY_F5", "Закрыл дверь");        tsfield[6] = prefs.getString("KEY_F6", "Выключил везде свет");        tsfield[7] = prefs.getString("KEY_F7", "Вынес мусор");        //Получаем настройки текста заголовка        String hellotext = prefs.getString("hellotitletext", "");        switcharray[6] = findViewById(list_of_switches[6]);        switcharray[7] = findViewById(list_of_switches[7]);        //Получаем настройки количества полей        String sixfields = prefs.getString("sixfields", "true");        String sevenfields = prefs.getString("sevenfields", "false");        String eightfields = prefs.getString("eightfields", "false");        if (sixfields.equals("true")){            switcharray[6].setVisibility(View.GONE);            switcharray[7].setVisibility(View.GONE);        }        else if (sevenfields.equals("true")) {            switcharray[6].setVisibility(View.VISIBLE);            switcharray[7].setVisibility(View.GONE);        }        else if (eightfields.equals("true")) {            switcharray[6].setVisibility(View.VISIBLE);            switcharray[7].setVisibility(View.VISIBLE);        }        //Создаем массив из TextView        TextView[] textarr = new TextView[8];        //Каждому переключателю назначаем текст из итерации поля tsfield        for (int i=0; i<8;i++){            textarr[i] = (TextView) findViewById(list_of_switches[i]);            textarr[i].setText(tsfield[i]);        }        //Назначаем текст заголовка            TextView textView5 = (TextView) findViewById(R.id.textView5);            textView5.setText(hellotext);        //Отображать заголовок, если соотв. поле заполнено        if(!hellotext.matches(""))        {            textView5.setVisibility(View.VISIBLE);        }        //Создаем связь каждого элемента переключателя по id из XML с соответствующей переменной типа SwitchCompat        for (int i=0;i<9;i++) {            switcharray[i] = findViewById(list_of_switches[i]);        }        //Создаем связь кнопки по id bt_next из xml переменной NextButton        NextButton = findViewById(R.id.bt_next);        //Используем SharedPreferences = "save"        SharedPreferences sharedPreferences = getSharedPreferences("save"                , MODE_PRIVATE);        //При первом запуске - все переключатели в False        for (int k=0; k<9; k++) {        switcharray[k].setChecked(sharedPreferences.getBoolean("value"+k, false));        }        //При переключении переключателей сохраняем данные, а также, проверяем их при повторном запуске        for (int k=0; k<9; k++) {            final int finalK = k;            switcharray[k].setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    if (switcharray[finalK].isChecked()) {                        //когда переключатель включен                        Reset = true; //                        switcharray[finalK].setBackgroundColor(Color.parseColor("#c8a2c6"));                        SharedPreferences.Editor editor = getSharedPreferences("save"                                , MODE_PRIVATE).edit();                        editor.putBoolean("value" + finalK, true);                        editor.apply();                        switcharray[finalK].setChecked(true);                    } else {                        //когда переключатель выключен                        SharedPreferences.Editor editor = getSharedPreferences("save"                                , MODE_PRIVATE).edit();                        editor.putBoolean("value" + finalK, false);                        Reset = false;                        switcharray[finalK].setBackgroundColor(Color.TRANSPARENT);                        editor.apply();                        switcharray[finalK].setChecked(false);                    }                }            });        }        //Кнопка открытия страницы настроек        NextButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                //Go to next activity                Intent intent2 = new Intent(MainActivity.this, Activity_settings.class);                startActivity(intent2);            }        });    }}

Следующим этапом будет написание кода для корректной работы макета Activity_Settings.XML, а логика его такова:

  • Введенные пользователь записи сохраняются даже после перезапуска приложения

  • Количество полей соответствуют числу, заданному в настройках из макета Activity_Advanced.xml

  • А также, должны работать оставшиеся кнопки меню.

Код по спойлером: 124 строчки
package com.bb.myapplication;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.content.SharedPreferences;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;public class Activity_settings extends AppCompatActivity {    //Initialize Variable    Button btBack;    Button fcSubmit;    Button btAdvanced;    //Ассоциируем поля ввода с переменными с помощью массива    EditText[] InputFields = new EditText[8];    //Назначаем полям значения по умолчанию и сохраняем их в Intent    String[] tsfield = new String[8];    //Создаем массив элементов из XML по id    public int[] list_of_fields = {            R.id.inputField0,            R.id.inputField1,            R.id.inputField2,            R.id.inputField3,            R.id.inputField4,            R.id.inputField5,            R.id.inputField6,            R.id.inputField7,    };    private SharedPreferences prefs;    //Создание формы / открытие приложения    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_settings);        //Назначаем полям значения по умолчанию и сохраняем их в Intent        prefs = getSharedPreferences("MY_DATA", MODE_PRIVATE);        //Получаем данные по количеству используемых полей        String sixfields = prefs.getString("sixfields", "true");        String sevenfields = prefs.getString("sevenfields", "false");        String eightfields = prefs.getString("eightfields", "false");        EditText inputField71var = (EditText) findViewById(list_of_fields[6]);        EditText inputField81var = (EditText) findViewById(list_of_fields[7]);        if (sixfields.equals("true")){            inputField71var.setVisibility(View.INVISIBLE);            inputField81var.setVisibility(View.INVISIBLE);        }        else if (sevenfields.equals("true")) {            inputField71var.setVisibility(View.VISIBLE);            inputField81var.setVisibility(View.INVISIBLE);        }        else if (eightfields.equals("true")) {            inputField71var.setVisibility(View.VISIBLE);            inputField81var.setVisibility(View.VISIBLE);        }        tsfield[0] = prefs.getString("KEY_F0", "Выключил газ");        tsfield[1] = prefs.getString("KEY_F1", "Выключил воду");        tsfield[2] = prefs.getString("KEY_F2", "Покормил кошек");        tsfield[3] = prefs.getString("KEY_F3", "Закрыл окна");        tsfield[4] = prefs.getString("KEY_F4", "Выключил Интернет");        tsfield[5] = prefs.getString("KEY_F5", "Закрыл дверь");        tsfield[6] = prefs.getString("KEY_F6", "Выключил везде свет");        tsfield[7] = prefs.getString("KEY_F7", "Вынес мусор");        //Назначаем полям ввода текст из SharedPreferences        for (int i=0; i<8; i++) {            InputFields[i] = (EditText) findViewById(list_of_fields[i]);            InputFields[i].setText(tsfield[i]);        }        //Создаем переменные для кнопок        btBack = findViewById(R.id.bt_back);        fcSubmit = findViewById(R.id.submit_fc);        btAdvanced = findViewById(R.id.btAdvanced);        //Кнопка Назад        btBack.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                //Go back                Intent intent = new Intent (                        Activity_settings.this,MainActivity.class                );                startActivity(intent);            }        });        //Кнопка Расширенные настройки/Дополнительно        btAdvanced.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                //Open Advanced Settings                Intent intent = new Intent (                        Activity_settings.this,Activity_advanced.class                );                startActivity(intent);            }        });    }    //Ссылка-значок на внешний ресурс - ссылка на мой телеграм    public void tglink(View view){        Intent myWebLink = new Intent(android.content.Intent.ACTION_VIEW);        myWebLink.setData(Uri.parse("https://t.me/EndlessNights"));            startActivity(myWebLink);    }    //Кнопка Сохранить данные    public void SaveData(View view)    {        for (int i=0; i<8;i++) {            tsfield[i] = InputFields[i].getText().toString();        SharedPreferences.Editor editor = prefs.edit();        editor.putString("KEY_F"+i, tsfield[i]);            editor.apply();        }        // Открываем главную страницу        startActivity(new Intent(getApplicationContext(), MainActivity.class));    }}

И наконец опишем логику работы последнего окна в приложении - с Дополнительными настройками:

  • Количество полей для отображения - в данном случае выбор с помощью радиокнопок - 6, 7 или 8 полей.

  • Текстовый заголовок, который пользователь может ввести и который будет отображаться на главной странице/активности.

  • Также, текстовый заголовок и выбранное количество полей с помощью радиокнопок должны сохранять свое состояние даже после перезапуска приложения.

  • И наконец должны работать оставшиеся кнопки меню.

Код под спойлером: 134 строчки
package com.bb.myapplication;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.content.SharedPreferences;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.CompoundButton;import android.widget.EditText;import android.widget.RadioButton;import android.widget.RadioGroup;import android.widget.Switch;import android.widget.TextView;public class Activity_advanced extends AppCompatActivity {    Button btBack;    //Назначаем радиокнопкам значения по умолчанию    Boolean sixbool = true;    Boolean sevenbool = false;    Boolean eightbool = false;    private SharedPreferences prefsadv;    //Поле ввода текста для заголовка    private EditText hellotitletext;    RadioGroup rdGroup;    //Переменные для радиокнопок    public RadioButton r1, r2, r3;    //Переменные для передачи состояния из boolean в sharedPrefs    String sixdata;    String sevendata;    String eightdata;    Switch bgswitchvar;    private SharedPreferences prefs;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_advanced);        bgswitchvar = findViewById(R.id.bgswitch);        prefsadv = getSharedPreferences("MY_DATA", MODE_PRIVATE);        rdGroup = (RadioGroup)findViewById(R.id.radioGroup);        //Поле заголовка        String hellotitletext1 = prefsadv.getString("hellotitletext","");        hellotitletext = (EditText) findViewById(R.id.hellotitletext);        hellotitletext.setText(hellotitletext1);        //Ассоциируем переменные с полями по id из xml        r1 = findViewById(R.id.sixfields);        r2 = findViewById(R.id.sevenfields);        r3 = findViewById(R.id.eightfields);        //При нажатии на радиокнопку, вызываем функцию Update с заданным ключом        r1.setChecked(Update("rbsix"));        r2.setChecked(Update("rbseven"));        r3.setChecked(Update("rbeight"));        //При нажатии первой кнопки добавляем True с ключом rbsix в RBDATA        r1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {            @Override            public void onCheckedChanged(CompoundButton compoundButton, boolean r1_isChecked) {                SaveIntoSharedPrefs("rbsix", r1_isChecked);            }        });        //При нажатии второй кнопки добавляем True с ключом rbsix в RBDATA        r2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {            @Override            public void onCheckedChanged(CompoundButton compoundButton, boolean r2_isChecked) {                SaveIntoSharedPrefs("rbseven", r2_isChecked);            }        });        //При нажатии третьей кнопки добавляем True с ключом rbsix в RBDATA        r3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {            @Override            public void onCheckedChanged(CompoundButton compoundButton, boolean r3_isChecked) {                SaveIntoSharedPrefs("rbeight", r3_isChecked);            }        });        //Back button        btBack = findViewById(R.id.btBackadvanced);        btBack.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                //Go back                Intent intent = new Intent (                        Activity_advanced.this,Activity_settings.class                );                startActivity(intent);            }        });    }    //Сохранение данных в SharedPreferences - ожидая ключ и значение булева типа    private void SaveIntoSharedPrefs(String key, boolean value){        SharedPreferences sp = getSharedPreferences("RBDATA",MODE_PRIVATE);        SharedPreferences.Editor editor = sp.edit();        editor.putBoolean(key,value);        editor.apply();    }    //Функция обновления значения в SharedPreferences    private boolean Update(String key){        SharedPreferences sp = getSharedPreferences("RBDATA",MODE_PRIVATE);        return sp.getBoolean(key, false);    }    //Сохраняем данные по количеству полей    public void SaveDataAdvanced(View view)    {        int checkedId = rdGroup.getCheckedRadioButtonId();        if(checkedId == R.id.sixfields) {            sixbool = true;            sevenbool = Boolean.FALSE;            eightbool = Boolean.FALSE;        }        else if (checkedId == R.id.sevenfields){            sevenbool = true;            sixbool = Boolean.FALSE;            eightbool = Boolean.FALSE;        }        else if (checkedId == R.id.eightfields){            eightbool = true;            sevenbool = Boolean.FALSE;            sixbool = Boolean.FALSE;        }        sixdata = String.valueOf(sixbool);        sevendata = String.valueOf(sevenbool);        eightdata = String.valueOf(eightbool);        String hellofield = hellotitletext.getText().toString();        SharedPreferences.Editor editor = prefsadv.edit();        editor.putString("sixfields", sixdata);        editor.putString("sevenfields", sevendata);        editor.putString("eightfields", eightdata);        editor.putString("hellotitletext", hellofield);        editor.apply();        startActivity(new Intent(getApplicationContext(), MainActivity.class));    }}

Подготовка приложения к публикации

Для отладки и проверки работоспособности приложения советую вам использовать настоящее устройство на Android, так вы сразу сможете отследить наличие, как минимум проблем с оформлением.

Здесь я приложил видео-инструкцию, как подключить свой смартфон к Android studio для отладки вашего приложения. На видео вы можете заметить первую версию данного приложения с очень плохим кодом:

Регистрация в Google Play

Для публикации приложения нам следует создать специальный аккаунт разработчика, вот прямая ссылка.

Далее вам предстоит оплатить пошлину в $35 за возможность публиковать приложения, это почти в 3 раза дешевле, чем в Steam, при том, что Steam просит $100 за каждое публикуемое приложение/игру, даже бесплатное, а с аккаунтом разработка, в Google Play вы можете публиковать несчётное множество приложений.

После оплаты и успешной авторизации в консоли разработчика, необходимо нажать на синюю кнопку "Создать приложение", далее заполнить все необходимые поля:

После создания приложения в консоли разработчика Google Play, необходимо перейти в раздел Рабочая версия и нажать на кнопку Создать новый выпуск. Вам предложат получить электронную подпись для вашего приложения с расширением *.jks, с помощью которой вам предстоит подписать свое первое приложение, а также, все дальнейшие выпуски с обновлениями.

Возвращаемся в Android Studio и необходимо заполнить немного информации о нашем приложении, для этого нажимаем File>Project Structure и заполняем поля Version Code и Version Name - без них Google Play Google Play не допустит ваше приложение до публикации:

Наконец, переходим в следующий раздел: пункт меню Build>Generate Signed Bundle / APK

В открывшимся окне выбираем APK. В подразделе Key Store Path выбираем Create new, далее заполняем все поля (прямая ссылка на официальную инструкцию), далее данный ключ потребуется загрузить в консоль Google Play. Затем вернемся в Android Studio и после ввода всех необходимых данных, нажимаем Next

В следующем окне отмечаем все чекбоксы, выбираем release и нажимаем Finish - Android Studio скомпилирует подписанное приложение, которое можно опубликовать в Google Play.

Итог

После загрузки файла приложения APK потребуется заполнить множество форм и подготовить множество материалов: описание на разных языках (если необходимо), изображения на разных языках (надписи на изображениях я имею в виду), логотипы, иконки разных размеров, скриншоты со смартфона и планшета.

Наконец отправляем приложение в публикацию. Сотрудники Google Play будут проверять ваше приложение в течении 2 недель, судя по официальным данным. Данное приложение рассматривали в течении 5 суток. Также, стоит учесть, что каждое обновление, также, будут проверять, но на обновления уходит не более 2-3 суток.

Ссылка на GitHub, как обещано. Ссылка на приложение в Google Play.

Подробнее..

Wild Horizon. Обзор наших первых изменений

02.06.2021 00:12:39 | Автор: admin

Очередной выпуск "игровой газеты". Изменения на первой полосе. Ответы на вопросы.

Доброго времени суток, уважаемый читатель. После того, как был опубликован предыдущий пост, стало поступать множество разных вопросов. Благодарю всех, кто проявил интерес к проекту.

Мы услышали все пожелания, учли наши ошибки, обратили внимание на жалобы.

Проект находится на стадии доработки.

Краткие ответы на ваши вопросы:

Почему мало русского языка?! За прошедшие десять дней мы перевели игру на 95% на русский язык, временно оставив на английском языке некоторые кнопки, исходя из технической проблемы.

Непонятно, что делать! В данный момент готовим подробное начальное обучение, которые полностью введет игрока в курс дела.

На каком движке игра? Unity. Работали на нем ранее, полностью устраивает.

Планируете ли искать издателя? Он нашел нас сам. Сейчас находимся в постоянном контакте с издателем, смотрим метрики, выполняем начальные условия. Пришлось временно отключить некоторые функции игры, включая и рекламу.

Будет ли боевая система? Да, сейчас активно рисую поселения индейцев, спрайты людей, спрайты бандитов. В защиту поселения будут выступать башни, стены, войска в городе, шериф.

Делали ли рекламу, покупали трафик? Нет, на продвижение игры не пострадал ни один рубль. Продвижение это всегда грамотное вливание огромных сумм. Думаю с этим в данных реалиях может справиться только издатель или довольно крупная компания.

Разрешение игры режется, не видно названий иконок. Программист Александр провел огромную работу по оптимизации экранов под разные форматы. В моем распоряжение есть убогий вытянутый формат экрана Samsung а51, наверное один из самых неудобных в плане экрана, с которого и начали замечать проблемы. Проблема решена для него и остальных основных форматов.

Samsung а51Samsung а51

Будут ли еще добавлены ресурсы? Да, раз в неделю добавляем по одной шахте для разных металлов.

ШахтыШахты

Как мне набрать людей / рабочих? Они приходят сами раз в пол часа, а также при строительстве домов. Теперь вы можете изучать, крафтить разные инструменты, снаряжать рабочих и назначать их на работу в ту или иную область карты. Инструменты и снаряжение имею разные уровни, делаются из разных материалов и в зависимости от качества дают повышенный бонус к производству.

Планируете ли внедрять еще персонажей? На данный момент в игре 8 персонажей, но 25 полностью прописанных заготовок. Всех персонажей четко прописывали в табличке, что бы не повторялись бонусы и каждый персонаж был бы уникальным.

Работаешь ли ты еще где то? Да, безусловно, дизайн мое всё, а проект это что-то вроде хобби, которое в будущем хотелось бы превратить в работу.

Также в комментариях под постом и в личку мне постоянно пишут о том, что бы сделал пост о процессе рисования данного проекта. Терпение, господа, терпение. Я помню, обязательно сделаю, в перерыве между основной работой и работой над проектом.

Проект дает интересный опыт каждому из нас, учит нас думать иначе, искать ошибки там, где их не должно быть. До нужного нам результата еще далеко, но я очень рад постоянно получать от вас обратную связь, видеть как проект перевалил за 300+ установок, как органически приходят люди с разных стран. Забавный факт! На втором месте по скачкам - Корея. Хз как так получилось.

Большинство из вас знает, что в разработке игры довольно мало романтики, много нагрузок и много ошибок. Слишком много, они повсюду. Но для меня это все же начальное детище, на которое просто приятно смотреть и не осознавать, что ты на пару с приятелем это смог сделать)

Спасибо за внимание, задавайте вопросы, присылайте пожелания, а мы в свою очередь сделаем все, что бы воплотить в жизнь больше интересных и полезных функций.

Любите игры, играйте в игры!

Подробнее..

Открылся набор в Indie Games Accelerator и Indie Games Festival от Google Play

14.06.2021 12:13:27 | Автор: admin

Indie Games Accelerator и Indie Games Festival две программы для независимых (инди) разработчиков мобильных игр, организованных командой Google Play. Программы направлены на то, чтобы помочь небольшим игровым студиям и разработчикам стать популярнее в Google Play независимо от того, на какой стадии находятся их проекты.

В этом году обе программы пройдут в онлайн-формате, заявки принимаются до 1 июля подробности под катом.

Для нас важно поддерживать не только крупные международные компании, но и небольшие инди-команды благодаря своей креативности и увлеченности играми, они создают уникальные и интересные проекты. Если вы работаете над уникальным проектом и хотите, чтобы о нем узнал мир, предлагаем вам принять участие в одной (или обоих сразу) из наших программ Indie Games Accelerator и Indie Games Festival.

Каждая из программ направлена на то, чтобы помочь небольшим игровым студиям стать популярнее в Google Play независимо от того, на какой стадии находятся их проекты: в акселератор принимаются проекты на этапе идеи или прототипа, фестиваль подойдет для игр, находящихся в активном оперировании. Заявки на обе программы принимаются до 1 июля.

Indie Games Accelerator: обучение и менторская поддержка

Эта программа разработана для начинающих инди-разработчиков, которые работают над прототипами будущих игр или делают тестовые релизы.

Проекты, которые пройдут отбор и станут участниками акселератора, смогут присоединиться к 12-недельной образовательной программе, а также получат возможность поработать над своими проектами вместе с экспертами из Google, крупных игровых студий и венчурных фондов. Rovio, Game Insight, Zynga, Play Ventures, Unity Technologies, Belka Games с полным списком менторов и условиями участия можно ознакомиться здесь.

В этом году в акселерационной программе участвуют более 70 стран, заявки на Indie Games Accelerator из России, Украины и Беларуси будут приниматься впервые!

Indie Games Festival: промо-кампании для финалистов

Эта программа разработана для небольших команд, которые недавно выпустили игру и хотят дальше работать над проектом без помощи паблишера или инвесторов.

Основные критерии отбора: инновационность, увлекательность и дизайн. Среди призов: фичеринг на Google Play и промо-кампании для 3 игр-победителей стоимостью 100 000 евро.

Условия участия: в программе участвуют 29 стран Европы, включая Россию, Украину и Беларусь; максимальное количество человек в команде 50, игра должна быть выпущена на Google Play не ранее 3 марта 2020 г. Подробнее с правилами участия и критериями отбора можно ознакомиться здесь.

В прошлом году в финал конкурса прошло три проекта из России: My Diggy Dog 2 от King Bird Games, Color Spots от UX Apps и Tricky Castle от Team Tricky подать заявку можно до 1 июля.

Подробнее..

Дайджест интересных материалов для мобильного разработчика 386 (15 21 марта)

21.03.2021 16:08:22 | Автор: admin
В нашей новой подборке троя в библиотеке, автотестирование и полезные протоколы, уязвимости Android и снижение комиссии Google Play, борьба с читерами, человеческое общение, цена покупок, Nest с радаром и многое другое. Подключайтесь!



Этот дайджест доступен в виде еженедельной рассылки. А ежедневно новости мы рассылаем в Telegram-канале.

iOS

Память в Swift от 0 до 1
Погружение в автотестирование на iOS. Часть 4. Ожидания в XCUITest
Работа с сложными JSON-объектами в Swift (Codable)
Коста Элефтериу, создатель FlickType, подал в суд на Apple
Александр Зимин: история победы в Telegram Contest 2021
Библиотека XcodeSpy заражает разработчиков с Xcode трояном
Количество работающих в экономике iOS-приложений в Европе выросло на 7%
Swift 5: полезные протоколы, чтобы писать как профессионал
Реверс-инжиниринг Bluetooth-устройств
Как уменьшить и оптимизировать размер iOS-приложения?
Создание настраиваемого UITextField с помощью Combine
Глубокое погружение в Функции в Swift
Список UICollectionView с интерактивным кастомным заголовком
Чистый Swift: объяснения и шаблоны
Тестирование push-уведомлений в iOS в конвейерах CI/CD
Протоколы в Swift
Реализация модификатора OnChange в SwiftUI для iOS 13
Xcodes.app: много Xcode на выбор

Android

Выходим на рынок Huawei, или Как мы адаптировали приложение для работы с HMS
Большой разговор с новым Kotlin Project Lead Романом Елизаровым
Готовьсь, цельсь, пли! Как не обжечься при сборке Gradle-приложения, и настолько ли всё серьезно?
0x7E5 Рассуждения о главном
Борьба за жизни переменных. Или как я попытался упростить жизнь Android разработчикам
Материалы митапа для андроид-инженеров: поиск проблем сборки, защита от них и работа с Gradle
Уязвимости Android 2020
Android запрещенные приемы
От компьютеров к мобильным устройствам: вывод игр на новые платформы
Android Broadcast: Собеседование в прямом эфире 2. Livecoding. Middle Android Dev
Android Broadcast: новости #7
Плитки в Wear OS открыли для всех
Google снижает комиссию Play до 15%
Компилируйте меньше с SOLID
Использование возможностей дизайн-языка Android
Добавьте вашему приложению жизни
Как мы разработали компонент, который повысил удобочитаемость, масштабирование и тестирование
10 ошибок, которые я сделал как Android-разработчик, но вы не должны
Лучшая обработка состояний между ViewModel и Composable
Создаем приложение с несколькими темами на Android
11 самых популярных библиотек Kotlin на 2021 год
Создаем плагин Android Studio Show layout bounds
Давайте сделаем приложение с таймером обратного отсчета с помощью Android Compose
Tinder-Like: Tinder на Jetpack Compose
Jetpack Release Tracker: отслеживание AndroidX
SegmentedProgressBar: прогресс-бар как в историях Instagram

Разработка

Первые пять шагов для перелома ситуации с читерами в PvP-шутере
Детские шалости: как Roblox стала одной из самых дорогих игровых компаний современности
Минимальное PWA
Автоматизация тестирования мобильных приложений. Часть 2: предусловия, верификация элементов и независимость шагов
Курс тестировщика пройден. А дальше что?
Мобильное настоящее М.Видео: телепортация была стремительной
Flutter вот-вот завоюет Web
Как все-таки экономить на мобильной разработке?
С чего начать изучение Flutter в 2021 году
Адаптация таблиц под мобильные устройства
Обзор мобильного приложения Team
Самый полный список метрик тестирования на русском языке
Podlodka #207: дебаггинг
Flutter Dev Podcast #26: Flutter 2.0
Redmadrobot открывает весеннюю стажировку
Aurora UI: новый визуальный тренд на 2021 год
LinearB объясняет происходящее в проектах разработки
Дизайн приложений: примеры для вдохновения #36
Верхняя или боковая панель навигации: что лучше подходит для вашего продукта?
Как улучшить понимание интерфейса с помощью интуитивных действий
Принципы психологии, которые следует знать каждому продуктовому дизайнеру
Kotlin Multiplatform панацея для разработки мобильных приложений?
5 наиболее часто задаваемых вопросов в собеседованиях программистов в Amazon
Расширения Visual Studio Code для повышения производительности в 2021
Мой опыт собеседования в Google
Будущее приложений: декларативные UI и Kotlin MultiPlatform
Как сделать UI-звуки для игры
10 шаблонов проектирования, которые должен знать каждый архитектор ПО
UX-советы по оптимизации встроенных покупок в играх
Как работать с трудными людьми в программных проектах
Закон Теслера. Вот почему вы не можете сделать UX проще.
Мои 3 самые большие неудачи как разработчика
5 способов увеличить скорость разработки
4 необычных способа улучшить свои навыки программирования
Взламываем код-интервью с помощью этих 5 реальных функций
5 главных ошибок, которые я совершил, когда был нубом в программировании
Clone Wars: клоны популярных проектов

Аналитика, маркетинг и монетизация

Маркетологи в мобайле: Максим Шатерник (Gameloft)
myTracker интегрировался с Google AdMob
Mobile People Talks: Анализируй это аналитика мобильных приложений
Как мы делаем Sleepy: монетизация, первая сессия и paywall
Hi Marley: человеческое общение
Gucci начинает продажи виртуальных кроссовок
Средняя цена на покупки в приложениях выросла на 50% с 2017 года
Apple согласилась на предустановку российских приложений
Основные метрики мобильного приложения

AI, Устройства, IoT

Видеоаналитика М.Видео-Эльдорадо: 30 000 камер, 1 компьютер и нейросеть
Bluetooth Low Energy: подробный гайд для начинающих. Bluetooth Mesh
Google выпускает новый Nest Hub с радаром

< Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку пришлите, пожалуйста, в почту.
Подробнее..

Какой хороший Xiaomi GetApps. Не даёт опубликовать обновление приложения и сам его просит

06.07.2020 16:22:04 | Автор: admin

Статья и голосование о том можно ли пользоваться Xiaomi GetApps совместно или (упаси Боже) вместо Google Play, если ты разработчик.


Присказка
Я занимаюсь разработкой мобильного приложения и размещал его в Google Play.
Потом узнал, что какая-то третья фирма разместила его в Xiaomi GetApps.
Я захотел сам контролировать процесс публикации приложений в Xiaomi GetApps
Для этого нужно было подписать пустой проект своим ключом, по-моему.
Получилось.

Сказка
И вот, недавно, решил я обновить своё приложение в Xiaomi GetApps.
Загрузил новую версию (нужно было ещё загружать каждый раз иконку приложения и описание не только нововедений, но и описание самого приложения).
Смотрю, а регион распространения только Mainland China.

И другой нельзя выбрать, хотя приложение доступно в клиенте GetApps в России.

Ну думаю, ладно, отправил на проверку.
Неделю оно там лежало и никакого решения по новой версии не было.
Вдруг приходит весёлое письмо:

Мол, юзеры просят новую версию, что ты её не выкладываешь?
Я пишу по обратному адресу: overseas-dev@xiaomi.com
Что мол, я уже выложил новую версию, почему Вы не рассматриваете моё приложение?
Почти сразу приходит отказ в публикации новой версии приложения и текущую версию приложения тоже снимают с публикации
Причина в том, что приложение не переведено на Китайский язык.

Я говорю: Так я не хочу в Китае распростаранять своё приложение, хочу в США, Европе и России.
Они почти сразу: Ок. выйдите и зайдите в консоль разработчика снова.

Я захожу в консоль разработчика и вижу следующее:

Ну Россия есть, уже спасибо. А Украина? А СНГ? А Европа? Представлена только Испанией?

Ладно думаю, пусть будет только Россия, хочу опубликовать новую версию (текущая версии приложения так и не опубликована).
Хочу опубликовать, а кнопка публикации заблокирована.


Ну я снял disabled=disabled


Тогда хоть начали показываться ошибки. Сначала GetApps сказал мне, что, раз приложение только на Русском, то его можно публиковать только в России. А в/на Украние, Белоруссии и Германии рускоязычных очевидно нет? Хотя европейских стран вообще нет в моей GetApps console, кроме Испании.
Были ещё какие-то 1-2 ошибки, я поправил.
Ну думаю опубликую. Нажимаю и вижу:

Вижу ошибку Null. И что мне делать? написал на overseas-dev@xiaomi.com
Ноль реакции.

А в это время текущая версия приложения так и не опубликована, хотя была опубликована более года до этого.

Хотел позвонить в Российское представительсво компании Xiaomi по телефону горячей линии
+7-800-775-66-15, мне отвечает автоинформатор, что абонент не доступен.

Звук ответа автоинформатора: gofile.io/d/zf0DQI

Это было 06.07.2020 в 11:59
в 14:45 телефон горячей линии заработал. Можно написать об этом обо всём на service.global@xiaomi.com, пока жду ответа от overseas-dev@xiaomi.com
upd 06.07.20 15:56: написал на service.global@xiaomi.com, поставил в копию overseas-dev@xiaomi.com и дал ссылку на эту статью.

Кстати, на описание приложения в GetApps дают всего 400 символов.

На описание приложения дают 400 символов, Карл.

А на описание нововедений дают 500 символов:



GetApps console сейчас показывает, что приложение не опубликовано в GetApps:
NOTHING HERE

Это я ещё опустил, как мне отвечали на китайском.

Xiaomi GetApps это сказка.
Подробнее..

Опыт разработки первой мобильной игры на Unity или как полностью перевернуть свою жизнь

16.02.2021 16:13:42 | Автор: admin

От кого и для кого

Доброго времени суток! Меня зовут Николай, и я хочу рассказать свою историю и поделиться своим небольшим опытом в разработке своей первой игры. С чего начинал и какие трудности пришлось преодолеть на пути разработки. Статья ориентирована на тех, кто начинает, думает начать или уже разрабатывает свою первую игру. Зачем? Потому что на стадии разработки своей первой игры, сам не однократно читал статьи о подобном опыте, после прочтения которых "наматывал сопли на кулак" и продолжал разработку дальше. От идеи до выпуска в магазин.

Внимание! Статья получилось длинной, так что запаситесь чаем! Если не хочется долго читать, то выжимка из советов в концы статьи.

С чего все начиналось

Шел третий курс универа

По образованию я моряк, однако, после первого рейса, я понял, что перспектива отстуствия на "земле" по 6 месяцев в году меня не радовала, хоть по зарплате в этой отрасли никого не обижают.

Выбор направления

Появилась острая необходимость найти "дело", которое будет приносить удовольствие, не придется отрываться от современного мира на длительный срок и иметь финансовый достаток в перспективе сравнимый с моей по образованию профессией. Конец 4 курса универа и мой выбор пал на IT индустрию, а именно на python разработчика. Уделив 2 недели теории, в частности технической документации языка, я начал развивать логику и выполняя задачки каждый день на протяжении полугода, пока в конце декабря 2018 года не обнаружил геймдев.

А вот и Unity!

Выглядит комично или даже банально, но я повелся на клик-бэйт видео с подобным названием "Как сделать свою первую игру за 15 минут" или "Делаю крутую игру за 5 минут без регистрации и смс". Посмотрев данные материалы, в голове появилась мысль, выделить себе пару дней в своем графике, и утолить свое любопытство, установив данную среду разработки на свой компьютер. Потыкав разные кнопочки, и написав код методом "copy-paste", я пришел в неописуемый восторг! Моя творческая натура внутри меня ликовала. Ведь это было так приятно наблюдать за тем, что ты "сам" написал пару минут назад, сейчас заставляет кубик крутиться, перемещаться или менять цвет. Так уж вышло, что средой разработки установленной на мой компьютер оказалась Unity.

Почему Unity?

Он бесплатный, не такой сложный в освоении, большое сообщество и тонны ресурсов для самообучения, поэтому отлично подходит для начинающих разработчиков. Мобильный рынок заполнен проектами созданные на Unity. Даже такие крупные компании как Blizzard, Riot Games, CD Project RED выпустили всеми известные хиты как Hearthstone, Wild Rift и Gwent, используя эту платформу. Приняв волевое решение, я решил уйти в геймдев на пару с Unity.

Подготовка к разработке

Формирование идеи

Определившись с выбором рабочей платформы для разработки игры, я отправился читать статьи людей, у которых имелся уже хоть какой то опыт в данной сфере, чтобы выбрать нужное мне направление. ПК или смартфоны? 2Д или 3Д? Сингл или мультиплеер?
Прочитав большое количество статей и проанализировав их, все советы сходились к тому, чтобы:

  1. Проект не разрабатывать больше 2-х месяцев, иначе увеличивается вероятность потерять энтузиазм и он окажется на полке "потом доделаю" так не дойдя до выпуска;

  2. Проект должен быть простой, легкий, желательно иметь небольшую изюминку. Иначе нафантазировав себе в голове крутой ААА проект с сетевым режимом и открытом миром, рискуете себе "сломать зубы", потеряв всякую мотивацию к разработке и потеряться где то в пучине депрессии и отчаяния;

Мой выбор

2Д мобильная аркада с сетевым режимом до 6 человек , рейтинговой системой и вознаграждением. Разработка, которой заняла отнюдь не 2 , а все "12 месяцев".

Аргументы "за":

  • Мне показалось заставлять двигаться объекты будет проще, чем те же 3Д;

  • Мобильный рынок огромен и его доля более половины всей игровой индустрии;

  • Писать сюжеты для игр я не умею, да и опыта в этом нет никакого, поэтому я решил сделать упор на веселье. А играть всегда веселее вместе! Поэтому сетевая;

  • Продолжительность жизни игр с сетевым режимом дольше, где ты можешь соревноваться с друзьями за лучший результат, чем у игр, где простенький сюжет, пройдя которую ты забудешь и никогда не вернешься.

Аргументы "против":

  • Игра уже становилась не так уж проста, как советовали более опытные коллеги;

  • Сложность и продолжительность разработки для не опытного "птенца" увеличивалась многократно.

Аргументы "за" были очень привлекательны и я решил рискнуть. Как говорится - "Чем чёрт не шутит" и "Была не была"!

Знакомство с Unity и его изучение

Учится чему то с нуля, это как учится кататься на велосипеде. Главное стараться и упорно трудиться, и тогда рано или поздно точно должно получится.
Начинал с малого, а именно перемещал разные объекты в пространстве, писав самый примитивный код.

Совет: знайте, чтобы вы не делали или не хотели начать делать, это с вероятность больше 90% уже было сделано до вас. Научитесь правильно искать нужную информацию!!!

После полумесяца изучения Unity, было необходимо разработать какой то план разработки, которому бы я следовал. Держать все в голове было невозможно, да и нецелесообразно. Сейчас я использую обычный текстовый редактор, где записывваю свои мысли о реализации той или иной фичи, но для начала хватить и обычного листка бумаги и карандаша.

Совет: попытайтесь как можно точно расписать предполагаемый план, по которому будете разрабатывать свою будущую игру. Управление персонажем, основной геймплей, музыка и эффекты, механика игры, интерфес.

Как только я накидал определенный план действий и уже собирался начать делать свой первый будущей "шедевр", встал серьезный вопрос

Где я возьму картинки, музыку и остальные элементы для своей будущей игры? Ведь я совершенно не умею сам это создавать

На помощь пришел фирменный магазин Unity, а именно unityAssetStore. Замечательная площадка, где фрилансеры выкладывают свои работы с целью их продать, а разработчики могут приобрести их для использования в своих проектах, тем самым ускоряя разработку и экономя драгоценное время и нервы.
На пути всей разработки игры, да и после выпуска, мои знакомые и друзьям задают мне практически одни и те же вопросы.

А ты сам все это нарисовал? А музыку ты писал тоже сам?

Как можете догадаться, они получали отрицательный ответ на все подобного рода вопросы.

Совет: Не чурайтесь использовать чужие наработки или шаблоны, которые продают или прибегать к работе фрилансеров! Это взаимосвязанная выгода! Конечному пользователю все равно, сами вы рисовали самолетик несколько часов или потратили 10$ на его покупку в магазине, ведь главное результат!

Разумеется, необходимо иметь базовые навыки такие как изменения размера изображения, цвета или редактирование определеного участка звука.

Совет: Отслеживайте скидки на продаваемые ассеты в различным магазинах, особенно под новый год! Можно приобрести кучу ассетов по выгодной цене со скидкой до 90% в такое время.

Непосредственная разработка

Первые шаги

Закончив с подготовительной частью, я принялся за работу. Ввиду того, что я заканчивал университет, и было необходимо готовиться к квалификационным экзаменам и защите диплома. На разработку игры в день уходило не более 3 часов в день. Такой режим продолжался до самого начала лета 2019 года.

На этом этапе моя игра имела следующий вид:

Главное начатьГлавное начать

Разумеется, я сразу начал осваивать сетевой режим, расчитывая на это потратить не больше двух недель. Я еще никогда так не ошибался. Вместо предполагаемых 2-х недель, ушло не меньше 2-х месяцев только на освоение софта для сетевой игры. Сам контент для игры простаивал.

Совет: Не думайте, что сетевая игра, будет легче чем написать простенький сюжет. Это совершенно не так.

От простого к сложному

Так как я понятия не имел, как настроить управление на мобильном телефоне, я решил пойти по пути постепенного повышения сложности. Настроил управление для клавиатуры с мышью, наладил подбор, применение предметов, сделал простейший интерфейс игровой механики и его взаимодействие с игроком и прочие мелочи. Позже, я подобрался уже к управлению персонажем с помощью телефона.
Все это заняло очень много времени и сцена с непосредственной сетевой игрой уже выглядела так:

Эх, как же сильно была переработана финальная версия интерфейсаЭх, как же сильно была переработана финальная версия интерфейса

Интерфес и меню

Не малая важная часть разработки игры, о которой начинающие разработчики не задумываются это Меню, его визуальное оформление и работоспособность. Когда уже основная часть геймплея готова, появляется ложное чувство того, что проект уже готов, и можно завтра его готовить для публикации в магазине. К сожалению, это не делается за пару дней. Это тяжелая и рутинная работа, которая требует концентрации и повышенной ответственности. Когда что-то светиться, крутиться и перемещается в меню, это располагает к себе пользователя. Не зря же все крупные вендоры компьютерного желаза продают свой товар с большим акцентом на динамическую RGB подстветку, значит есть положительный результат!

Совет: Перед тем как создавать свое меню, поиграйте в разные игры подобного или смежного жанра. Выделите для себя полезные фичи интерфейса и меню. Что в них интересного и что вам нравится.

На этом этапе разработки, многие проекты так и не доходят до выпуска в мир. Тут несколько факторов способствуют:

  • усталость

  • потеря интереса

  • неувереность в своих силах

  • все кажется адом и этому нет конца и края

Совет: Скажу то, что я прочитал когда сам проходил этот этап. НЕ СДАВАЙСЯ! Как бы не было сложно, ни в кое случае НЕ СДАВАЙСЯ и НИ ШАГУ НАЗАД! Дойдя до самого конца ты познаешь лавину экстаза и самоудовлетворения от того, что ты не бросил все! И разумеется бесценный опыт!!!

Однопользовательский режим

Сетевая игра это, конечно, хорошо, но что если у пользователя отсуствует подступ к Информационно-Телекоммуникационной Системе Общего Пользования?(Интернет)
Разумеется, было принято решение сделать простенький сингл режим, где игрок будет собирать определенный ресурс на время, а ему попутно будут мешаться ИИ, затруднив выполнение миссии.
Две недели работы, и первоначальный вид был такой:

Концептуальные различие с финальной версией отстствуютКонцептуальные различие с финальной версией отстствуют

Оптимизация

Фух! Оптимизация это такая штука, о которой ты начинаешь задумываться, когда твой проект на смартфоне выдает 10-15 кадров в секунду с фризами и просадками до 4 кадров секунду. Как только тестирования проекта доходит до сборки его на телефоне, все встает на свои места. При разработке прилождений на мобильные смартфоны, оптимизация имеет очень важную роль. Ведь в них не скрывается такая вычислительная мощность как на ПК.

Я начал оптимизировать свой проект, только спустя 8 месяцев разработки. Из-за чего оптимизировать надо было много и долго:

  • картинки

  • материалы

  • звук

  • шейдеры

  • настройки камеры, рендеринга

  • интерфейс

  • скрипты

Это заняло у меня еще не меньше двух недель.

Совет: Не затягивайте с оптимизацией! Изучите сразу вопрос, как стоит правильно использовать определенные настройки в работе с теми или иными ресурсами в вашем проекте, чтобы добиться наилучшей производительности.

Одна голова хорошо, а несколько лучше

Обязательно спрашивайте мнение других людей о вашем проекте на разных этапах разработки. Разная точка зрения под разным углом даст хороший фидбэк и новые идеи для дальнейней работы. Не принимайте в свой адрес негативные отзывы о вашем проекте, как что то ужасное. Негативный отзыв, а еще лучше конструктивная критика - это невероятная удача и стимул сделать свой проект лучше!

Совет: Найдите так называемых "жертв", которых будете использовать в качестве тестировщиков среди ваших родственников, близких друзей и коллег по цеху. Брат, сестера, мама, папа, парень, девушка, друг, подруга, кто угодно. Дайте ему смартфон с игрой, посадите его рядом и просто наблюдайте, что ему не нравится, а что нравится. Главное - просто молчите и смотрите!

Реклама и внутриигровые покупки

Настал черёд встроить в свой проект рекламу и сделать магазин. Кто бы что не говорил, но на одном энтузиазме далеко не уедешь и святым духом сыт не будешь. Посему, это необходимый блок разработки. Тут главное грамотно подойти к этому делу, чтобы игрок не "плевался" и выгода была для обеих сторон!

Софта для рекламных интеграций имеется множетство, в том числе и от самой Unity, так называемая Unity Ads. Однако, мой выбор пал на Google AdMob. Почему не Unity Ads? Почитав обзоры, я узнал, что контент рекламы содержит казино, рулетки и ставки. Тут уже на вкус и цвет, как говорится, но я не хочу чтобы реклама была связана с подобного рода сервисами. Я использовал межстраничную и рекламу с вознаграждением.

Совет: Реклама с вознаграждением, намного лучше, ведь игрок сам нажимает на просмотр рекламы, чтобы получить какие-либо "плюшки" в игре. Разработчик и пользователь в плюсе!

Покупки в игре, я реализовал подобным образом:

Финальная версия игры

"12 месяцев" кропотливой работы , и финальная версия выглядит примерно так:

Меню игрыМеню игрыСетевой ГеймплейСетевой Геймплей

Казалось бы, все сделано и осталось дело за малым, а именно опубликовать игру. Но не все так просто как кажется!

Совет: Тут необходимо открыть еще одно "второе" дыхание , к ранее уже открытым +100500

Публикация игры

Большим плюсом выбора Unity - кроссплатформенность, что позволяет один проект выпустить на всех желаемых платформах (Android, iOS,PC,WebGl и др). К моменту написания статьи игра была опубликована только для Android в Google Play Market, но не за горами ios в Apple Store.

Какие "подводные камни" имеются?

Технически публикация приложения в Google Play Market не составляет никакого труда всё интуитивно понятно и легко. Пройти проверку по возрастному рейтингу, загрузить картинки из игры, логотип и впринципе все готово.

Так в чем же проблема и где те самые "подводные камни"?

Политика конфиденциальности

Для публикации она не является необходимым элементом, однако, если в вашем приложении имеется реклама или внутриигровые покупки, то в кратчайшие сроки стоит обзавестись данной "бумажкой" и указать сссылку на неё в Google Play Console. К счастью, есть моножество ресурсов, которые генерирует данный документ за считанные секунды и сразу предлагают разместить на их сайте, удовлетворяя запросам гугла.
Если проигнорировать предупреждения от гугл, что у вас отсутствует политика конфидециальности, то приложение могут легко снять с публикации.

Совет: Не откладывайте на потом этот пункт, делайте его паралельно с публикацией!

Идентификатор клиента OAuth

Если у вас в игре имеется система достижений, рейтинга от гугл или вы хотя бы сохраняете данные игры в облаке от гугл, то необходимо, чтобы пользователь проходил процесс авторизации используя гугл аккаунт, а значит предоставлял некоторые разрешения на управления его данными. Теперь по порядку. При настройке игровых сервисов в Google Play Console, необходимо создать приложение для авторизации пользователя в Google Cloud Platforms, настроить учетные данные для идентификатора клиента OAuth, и Окно запроса доступа OAuth. Пожалуй это главный "подводный камень".
Сложность состоит не в его первоначальной настройке, чтобы сервисы исправно работали, а в том что приложение было опубликовано и не имело ограничений по количеству пользователей. Если вы намерены создавать крупнобюджетный проект, которые будет привлекать тысячи игроков, то вам придется обязательно пройти этот этап.

Сайт игры

Это не является обязательным пунктом, но лучше сделать сайт, где будут размещены новости вашего проекта, а так же политика конфиденциальности и прочие материалы для ознакомления. Оказывается в 2021 году сделать легкий и простой сайт достаточно просто. С шаблонами для разработки сайтов в Word Press, не долго думая, я останавливаюсь на нем. Для сайта необходим хостинг и собственный домен. Взвесив все "за" и "против", решил потратить пару тысяч рублей на его аренду, сроком на 48 месяцев и не "париться". В сети огромное количество предложений, так что проблем с этим тоже не было. Пару часов уходит на его настройку, и еще пару часов на наполнение его контентом. И вот уже есть свой собственный сайт для игры!

Совет: Чтобы получить заветную галочку во вкладке Окно запроса доступа OAuth в Google Cloud Platforms, иметь сайт игры и свой домен , где так же будет размещена политика конфиденциальности - является обязательным пунктом!

Совет: Так же, если используете рекламу от Google Admob, то сайт тоже необходим. В корневую папку вашего сайта добавляется файл app-ads.txt. Это позволяет рекламодателям понять, какие источники объявлений имеют право продавать рекламный инвентарь. Если не пройти авторизацию, то доход с рекламы будет сильно снижен!

GDPR

Еще одно бюрократическое препятствие осталось, на пути для публикации. Если ваше приложение имеет рекламу, то она может быть персонализированной, а значит ваше приложение собирает данные пользователей, чтобы успешно показывать рекламу. GDPR- (General Data Protection Regulation) -этозакон, принятый Европейским Парламентом, который описывает правила защиты данных для граждан ЕС. Это значит,чтобы показывать персональну рекламу, необходимо перед первым запуском вашей игры, пользователь должен принять соглашение, что ознакомлен с политикой конфиденциальности вашего приложения, а так же прочитать в каких целях будет использоваться его персональные данные и дать согласие/отказаться на их обработку. Разумееется это распространяется на резидентов из стран ЕС.

После выполнения всех выше изложенных пунктов, мое приложение успешно опубликовано в Google Play Market и не знает никаких проблем.

Краткая выжимка советов

  • Изучите рынок, и определитесь с направлением и жанром игры. Главное не стройте в начале "наполеоновские"планы, которые могут и не реализоваться!

  • Распишите план действий и пытайтесь четко следовать ему, попутно внося небольшие правки. Старайтесь укладываться в установленные планом сроки.

  • Обязательно спрашивайте мнение ваших близких и друзей о вашей игре на протяжении всей разработки.

  • Не стесняйтесь приобретать ресурсы для ускорения разработки и повышения качества своего проекта.

  • Старайтесь писать программный код максимально понятный вам и другим людям, чтобы его можно было прочитать спустя месяцы разработки и понять его смысл.

  • Изучите базовые навыки работы с редактированием изображений и звуков.

  • Соорудите себе в браузере пул полезных закладок с библиотекой различных ресурсов, имея быстрый к ним доступ.

  • Научитесь использовать на базовом уровне Git. Незаменимый помощник при разработке игры, чтобы контролировать внесенные изменения.

  • Последнее и наверно самое важное. Никогда не сдавайтесь , верьте в себя, упорно трудитесь и рано или поздно, но у вас все обязательно получится! Если получилось у меня и миллионов других начинающих разработчиков данного ремесла, то почему не должно получится и у вас!?

Заключение

Премного благодарен вам, что вы дочитали конца эту длинную статью! Надеюсь, что те кто только пробуют себя в роли разработчика, подчерпнут для себя некоторые полезные вещи и получат заряд мотивации, а "бывалые" найдут эту историю как минимум не скучной.

Не знаю, кто сказал, что разработка игр это веселое занятие. Это не разу не вёселое занятие, требующее повышенной концентрации, ответственности к деталям, высокого уровня самодисциплины и упорства. Интересно ли?! Разумеется да, иначе бы я не начинал этот путь. Играть в игры и делать их, это совершенно разные вещи. Но в любом случае, это безумно интересно! Сделанный выбор однажды в универе, полностью перевернул моё мышление и всю мою жизнь. Не бойтесь и дерзайте!

Если я где-то ошибся и был не прав - буду рад правкам и пожеланиям в комментариях. Готов ответить на любые вопросы по данной теме.

Чтобы не было недопониманий на счет даты релиза.

Впервые игра была опубликована 2 декабря 2019 года, и это было 10 месяцев разработки. После я был вынужден отдать долг своей родине. Срочную службу в армии я нес до 2 декабря 2020. После демобилизации, я сразу продолжил разработку. И 4 февраля 2021, после "12 месяцев" разработки, я выпустил проект.

Если Вам интересно посмотреть на результат моей работы, то вы можете найти в Google Play Market.

Название игры - Starlake

Подробнее..

Подробнее об обновленных правилах программы для разработчиков Google Play

08.04.2021 12:19:54 | Автор: admin

31 марта мы опубликовали обновленные правила программы для разработчиков Google Play. Изменения касаются разрешения на доступ ко всем хранящимся на мобильном устройстве файлам, неприемлемого контента (включая ненормативную лексику), азартных игр, а также игр, конкурсов и турниров с реальными денежными призами. Кроме того, мы добавили новые уточнения и примеры для уже существующих правил полный список изменений можно посмотреть в Центре правил. Все новые и существующие приложения должны быть приведены в соответствие с обновленными правилами до 5 мая 2021 г.

Конфиденциальность и безопасность пользователей имеют первостепенное значение для Google Play, поэтому мы постоянно работаем над нашими политиками и правилами. Джо Дэвис, менеджер Академии Google Play, объясняет новые правила в семиминутном видео (доступны субтитры на русском языке):

  • 0:45 All Files Access Permission

  • 1:30 Новостные приложения

  • 2:12 Пояснения для Personal & Sensitive User Data

  • 2:27 Пояснения для Families Ads & Monetization policies

  • 3:48 New Package (App) Visibility policy

Полный список изменений со ссылками на примеры можно посмотреть в Центре правил. Напоминаем, что все новые и существующие приложения должны быть приведены в соответствие с обновленными правилами до 5 мая 2021 г.

Дополнительный материал:

  • Developer Policy Center все правила Google Play и дополнительные материалы в одном месте. Для тех, кто предпочитает формат видео роликов, плейлист Google Play PolicyBytes.

  • Учебная программа о политиках и правилах Google Play на сайте Play Academy.

Подробнее..

Как написать симпатичный чейнджлог опыт Авито

25.05.2021 12:05:50 | Автор: admin

Привет! Меня зовут Гера, я продуктовый редактор вАвито. Пишу тексты для интерфейсов ирассылок, аещё чейнджлоги дляGooglePlay иAppStore. Это тексты, вкоторых рассказывается, что появилось вновой версии приложения. По-английски их ещё иногда называют what'snew или releasenotes.

Сам текст длястора лишь верхушка айсберга. Апод водой скрыто увлекательное приключение, которое требует наблюдательности, дипломатичности изадатков детектива.

Наиболее полезной статья будет дляразработчиков, продактов и начинающих редакторов. Япокажу, как написать интересный чейнджлог даже когда рассказать не очем.

А зачем оно всё

Возможно, ценность чейнджлогов очевидна не всем компаниям. Фейсбук отказался отуникальных текстов много лет назад и теперь повторяет шаблоны обисправленных ошибках. Необходимость рассказывать оновых фичах не пропала, просто дляэтого чаще стали использовать пуш-уведомления, письма, баннеры, сториз.

Есть ли какая-то логика вприменении шаблонов неизвестноЕсть ли какая-то логика вприменении шаблонов неизвестно

Сторы включают пользователям автоматическое обновление: многие и не знают, что загрузили новую версию приложения. App Store идёт дальше: раньше чейнджлоги жили вотдельной вкладке наглавном экране, но в2019году скрылись внастройках. Наиконке был счётчик необновлённых приложений, но и он пропал. Ктому же, оба стора не дают узнать, сколько людей прочитали текст.

Но мы вАвито ценим чейнджлоги. Они помогают бесплатно дотянуться доне самой многочисленной, приэтомнаиболее активной и преданной аудитории. Эти пользователи любят узнавать оновых фичах просто излюбопытства, интереса ктехнологиям или потому, что следят законкурентами. Вконце концов, это разработчики, которые могут однажды прочитать здоровский чейнджлог и захотеть прийти насобеседование.

Читать такие сообщения приятно. Особенно учитывая, что это пустышка новых фич врелизе не былоЧитать такие сообщения приятно. Особенно учитывая, что это пустышка новых фич врелизе не было

Мне кажется, свои редакторские навыки я развил вомногом благодаря чейнджлогам. Ведь это суть нашей работы: сначала разбираешься всложном вопросе, затем пишешь онём ёмко ичеловечно.

Процесс в Авито

Сжатые сроки

В Авито новые версии приложений выходят каждую неделю и дляAndroid, и дляiOS. Соответственно, каждую неделю требуются два чейнджлога. Приэтом часто разные: фича могла мильон лет существовать наiOS и только сейчас появиться наAndroid.

Если вы хотите узнать, как устроен выпуск приложений вАвито, загляните в статью вней много технических деталей.

Неуловимые изменения

Вместе с задачей начейнджлог редактор получает таблицу сизменениями врелизе.

Разобраться всмысле изначимости фич бывает жутко сложно: названия задач написаны разработчиками дляразработчиков, а не редакторов. Иногда большие изменения скрываются заневзрачным названием, азаярким техническое улучшение, которое пользователи могут инеощутить. Спросить урелиз-инженера, что интересного вэтой версии, нельзя: вАвито десятки команд и каждая работает надсвоим кусочком сервиса.

Типичные названия задач изтаблицы: какие-то иностранные колонки, богатые парсинги и чистые симуляторыТипичные названия задач изтаблицы: какие-то иностранные колонки, богатые парсинги и чистые симуляторы

Есть и ещё одна сложность. Почти все фичи сначала тестируются начасти пользователей всреднем наАвито одновременно крутятся 80экспериментов. Даже если изменение решают катить, отследить этот момент непросто. Фичу могут включить безрелиза набэкенде, тогда отдельной задачи и не появится.

Кто виноват? Что делать?

Детективная работа

Чтобы собрать информацию, нужно превратиться в сыщика идипломата.

Некоторые продакты сами пишут редактору, ноэто бывает редко. Релизы фич невсегда проходят гладко, ичейнджлог это последнее, очём думают менеджеры втакой момент. Поэтому приходится периодически писать продактам идоставатьих вопросами. Ведь редактору нужно непросто узнать, когда и какая фича раскатывается. Главное понять, как она работает и вчём еёценность дляпользователей иАвито.

Прежде чем обратиться кменеджеру, детективу приходится наводить справки исобирать улики. Дляэтого нужно спрашивать удругих редакторов, надкакими интересными фичами они работают. Общаться сдизайнерами и изучать их макеты. Ходить навстречи продуктовых команд, где они рассказывают освоих достижениях ипланах.

Написание чейнджлогов изменилось, когда я выведал обособой рассылке дляслужбы поддержки. Вней продакты, разработчики имаркетологи пишут озапускеважных фич итестах, и вподдержке знают, что ответить навопросы пользователей. Конечно, чтобы разобраться вобновлении, мне всё равно приходится подскакивать кабанчиком кответственным человечкам иобкашливать сними вопросики.

Есть и минус: теперь я получаю ворох писем, безкоторых жилось бы спокойнее. Например, озапрете продажи подержанных трусов наАвито. Но такова цена работы детектива.

Формальности

Когда чейнджлог написан, я согласовываю его спродактом. А если менеджер вотпуске сдизайнером, потому что онвсегда погружён вконтекст. Так удаётся избежать неточностей иубедиться, что акценты расставлены правильно.

Затем записываю текст в файлик систорией чейнджлогов он ведётся сиюля 2018года иотдаю релиз-инженеру, который заливает новую версию приложения встор.

И так подва раза каждую неделю. Не считая майских и новогодних каникул.

Советы по написанию

Теперь расскажу, очём важно помнить, чтобы чейнджлог не только вышел, ноиполучился хорошеньким.

Главная цель такого текста подсветить значимое дляпользователей изменение. Это может быть новая возможность, редизайн или исправленная ошибка.

На месте автора я бы задался вопросом: какая ценность в изменениях? Может, оптимизация ускорила загрузку страниц? Или новые цвета сделали приложение удобнее для людей с плохим зрением? Если ценности нет, то можно инерассказывать об измененияхНа месте автора я бы задался вопросом: какая ценность в изменениях? Может, оптимизация ускорила загрузку страниц? Или новые цвета сделали приложение удобнее для людей с плохим зрением? Если ценности нет, то можно инерассказывать об изменениях

Соблюдайте законы сторов

Поправилам GooglePlay иAppStoreчейнджлоги нельзя использовать вмаркетинговых целях, например рекламировать акцию, если она никак несвязана спродуктовым изменением. Нообязательно нужно упомянуть, что именно улучшено или исправлено.

Из-за неподходящего текста релиз может непройти проверку инераскатиться. Иногда сторы пропускают такие чейнджлоги, нориск слишком велик: можно подвести коллег, которым важно зарелизить приложение вовремя.

Так выглядят примерно 99,9% чейнджлоговТак выглядят примерно 99,9% чейнджлогов

Также помните олимитах. Это актуально скорее дляGooglePlay: внём ограничение 500символов. ВAppStore 4000, нужно ещё умудриться столько написать: это четверть этой статьи.

Перед отправкой проверяйте чейнджлог наошибки, если есть корректор, топоказывайте ему. Текст вAppStore нельзя заменить после того, как приложение прошло проверку, только если катить новую версию. ВGoogle Play чейнджлог можно поменять влюбой момент, нолучше доэтого недоводить.

Однажды я налажал и написал насколько раздельно, хотя в этом случае нужно было слитно. Чтобы исправить мою ошибку, релиз-инженеру пришлось катить внеплановую версиюОднажды я налажал и написал насколько раздельно, хотя в этом случае нужно было слитно. Чтобы исправить мою ошибку, релиз-инженеру пришлось катить внеплановую версию

Помните, очём икак уже писали

Человек видит чейнджлоги примерно водном итомже месте авAppStore даже может полистатьисторию версий. Поэтому начинайте иструктурируйте текст по-разному всоседних релизах.

У нас есть файлик с историей чейнджлоговУ нас есть файлик с историей чейнджлогов

Слова стало, теперь, исправлено итому подобные неизбежно будут встречаться чаще других. Но я слежу затем, чтобы они повторялись как можно реже, иначе тексты выглядят небрежно.

Непишите отестах

Тут две опасности. Во-первых, часть пользователей вообще неувидит изменения, поэтому дляних это бесполезная информация. Аво-вторых, даже те,кто попадут втест, могут лишиться фичи если эксперимент свернут.

Чейнджлог отесте выглядит так, словно вас чем-то поманили и сразу убрали приманку. И непонятно, что это было, где искать и как жить дальшеЧейнджлог отесте выглядит так, словно вас чем-то поманили и сразу убрали приманку. И непонятно, что это было, где искать и как жить дальше

Рассказывайте омасштабных изменениях

Если вы исправили опечатку или передвинули кнопку напару пикселей, вряд ли стоит обэтом писать.

Речь о фиче, которой могут воспользоваться практически все пользователи Авито, которые начнут создавать объявление. Не рассказать о таком было бы преступлениемРечь о фиче, которой могут воспользоваться практически все пользователи Авито, которые начнут создавать объявление. Не рассказать о таком было бы преступлениемКонечно, Яндекс.Картами пользуются не только вМоскве, но москвичей много и обновление дляних значимоеКонечно, Яндекс.Картами пользуются не только вМоскве, но москвичей много и обновление дляних значимое

Иллюстрируйте пользу

Если позволяет место, добавьте наглядных примеров, чтобы ценность изменения стала более явной.

Может показаться, что котики это ленивый пример. Но на Авито больше 100 тысяч объявлений с ними, одно милее другогоМожет показаться, что котики это ленивый пример. Но на Авито больше 100 тысяч объявлений с ними, одно милее другогоВсего одним словом зачем-то ВКонтакте эмоционально подсвечивает проблему, скоторой сталкивались многие. Идоступно рассказывает отехнических сторонахВсего одним словом зачем-то ВКонтакте эмоционально подсвечивает проблему, скоторой сталкивались многие. Идоступно рассказывает отехнических сторонах

Аккуратно говорите обошибках искорости работы

Иногда хочется написать, что ошибок стало меньше, ноэто редко будет правдой. Один исправленный недочёт может породить пяток других просто они пока будут незаметны. Поэтому стоит говорить оконкретных исправлениях.

Таже ситуация соскоростью истабильностью. Очень редко происходят настолько масштабные иуниверсальные изменения вприложении, что оно увсех начинает работать быстрее инадёжнее. Если это как раз такое обновление, нужно быть конкретными.

Это была неприятная проблема, но не суперстрашная. Поэтому уместно разбавить текст чем-то забавнымЭто была неприятная проблема, но не суперстрашная. Поэтому уместно разбавить текст чем-то забавнымWhoosh кратко и чётко описывает решённую проблему. Но без последнего предложения вполне можно было обойтись: оважном изменении уже рассказалиWhoosh кратко и чётко описывает решённую проблему. Но без последнего предложения вполне можно было обойтись: оважном изменении уже рассказалиТак Яндекс.Такси скоро разгонится допервой космической скорости. Нет ничего страшного вповторении, но это выглядит завиральноТак Яндекс.Такси скоро разгонится допервой космической скорости. Нет ничего страшного вповторении, но это выглядит завирально

Если шутите, то без кринжа

В Авито мы некасаемся политики идругих острых тем. Если шутка рождается сама походу написания, проверяемеё накринжовость, оскорбительность ипонятность.

Обязательно покажите чейнджлог нескольким людям. Непоймут инеулыбнутся откажитесь отидеи, это нетрагедия.

Было важно, чтобы релиз вышел вконце августа. Иначе опытные закатыватели банок написали бы, что нельзя сделать заготовки наосень осеньюБыло важно, чтобы релиз вышел вконце августа. Иначе опытные закатыватели банок написали бы, что нельзя сделать заготовки наосень осеньюТут Авиасейлс обыгрывает принятие поправок кКонституции. При этом обизменениях они сказали, так что формальности соблюденыТут Авиасейлс обыгрывает принятие поправок кКонституции. При этом обизменениях они сказали, так что формальности соблюденыВроде Тинькофф добавляет достаточно милую подпись, но не бывает такого, чтобы дождило увсех пользователей. Втакие моменты может создаться ощущение, что отебе не подумалиВроде Тинькофф добавляет достаточно милую подпись, но не бывает такого, чтобы дождило увсех пользователей. Втакие моменты может создаться ощущение, что отебе не подумали

Помните, что вы пишете для пользователей, анеколлег поцеху. Чейнджлог вроде тех, что ниже, может попасть впост вТелеграм-канале, ноубольшинства читателей скорее вызовет недоумение.

Хороший редактор как клей: собирает целое из разрозненного и не вытекает наружуХороший редактор как клей: собирает целое из разрозненного и не вытекает наружуЭто снова Авиасейлс, в принципе от них такого и ожидаешь. Но в тексте нет ни слова об изменениях релиз мог непройти проверкуЭто снова Авиасейлс, в принципе от них такого и ожидаешь. Но в тексте нет ни слова об изменениях релиз мог непройти проверку

Однажды у нас вышел милый чейнджлог опопулярной породе собак:

Но пользователей Авито так много, что кто-то всё равно непонял:

Непревращайтесь вроботов

Хотьипишем отехнических штуках, важно оставаться человеками.

В принципе тут чувствуешь, что с тобой говорит РЖД, а не человек В принципе тут чувствуешь, что с тобой говорит РЖД, а не человек

Что делать, если писать неочем

В Авито в 2020году на Android вышло 46релизов, и 16 то есть треть были счейнджлогами-пустышками. На то есть причины: иногда редактору не удаётся найти интересную тему, а иногда их действительно нет.

Раньше я писал новый текст длякаждого релиза, но понял, что это отнимает много сил. Теперь могу раз-другой повторить чейнджлог. Это позволяет выкроить время дляболее важных задач, ноприэтомпривлечь внимание кизменениям.

На случаи, когда всёже придётся выпускать пустышку, уменя есть заготовки. Писать можно оразном. Например, одавнишней, новажной фиче:

Или об интересном исследовании:

Можно написать что-то ситуативное например, привязаться кчемпионату мира пофутболу:

Или рассказать очём-то, что можно найти наАвито:

Если соблюсти формальности и сказать обисправлениях, можно аккуратно прорекламировать икакой-то свой проект:

Кратко: как писать симпатичные чейнджлоги

  • Постройте агентурную сеть. Человек, который пишет чейнджлог, должен знать обизменениях изпервых уст, либо понимать, ккому обратиться.

  • Говорите, что изменилось. Вряд ли вам нужно, чтобы релиз отклонили, особенно, если внём исправлена неприятная ошибка.

  • Не преувеличивайте. Если приложение нестало работать быстрее уабсолютного большинства пользователей, не стоит говорить, что всё внезапно начнёт летать.

  • Будьте последовательны. Чейнджлог ещё одна точка соприкосновения пользователя спродуктом. Если обычно общаетесь навы и,вообще, деловито, нестоит писать Зацени, обновление пушка!

  • Приносите пользу. Представьте, что вам нужно объяснить изменения бабушке, пока выедете влифте. Важно подсветить, что вобновлении интересного, как оно улучшит жизнь.

  • Аккуратнее с шутками. Когда вы придумаете нечто потешное, покажите чейнджлог нескольким людям. Если смешно только вам, отшутки лучше избавиться.

  • Делайте заготовки. Вам нужны тексты наслучаи, когда рассказать будет не очем. Обыграйте сценарии использования приложения, расскажите опроведённом исследовании, покажите занятную статистику, подсветите старую, но важную фичу.

Подробнее..

За что банит Apple(и Google)

27.05.2021 02:21:05 | Автор: admin

У платформодержателей мобильных сторов множество причин для блокировок. Если напрямую с этим не сталкиваться, то, кажется, что все просто - не нарушай описанные правила и все будет отлично. На деле не все блокировки легко предугадать простым следованием гайдлайнов.

Рассмотрим некоторые из них.

Покупки не через сервисы Google&Apple

Начнем с одной из самых известных сейчас блокировок - удаление игры Fortnite от Epic Games из мобильных сторов. Издатель решил, что отдавать 30 процентов комиссии с каждой покупки слишком много и сделал оплату в обход стандартного механизма In-app payment. Что, конечно, запрещено. И ни Apple, ни Google не захотели терять свой доход(хотя на некоторые послабления уже пошли Apple Google).

При этом нельзя забывать, что на самом деле оплата сторонними средствами возможна в приложениях, распространяемых в сторах. Например, можно продавать реальные товары(как в Ozon) или услуги(как Uber). Но нельзя продавать то, что потребляет пользователь в самом приложении(игровая валюта, скин на персонажа и т.п.)

COVID-19

Множество блокировок было ровно год назад. Большое количество разработчиков начали выкладывать разные приложения с ковид-тематикой(от агрегаторов статей и карт распространения до фейковых анализаторов на наличие болезни). При этом реальной информацией тогда еще мало кто владел.

Тут Apple и Google решили, что все такие приложения пора либо перестать публиковать, либо заблокировать, если уже прошли. Еще была схема с удалением из поисковой выдачи.

В итоге в мае сторы на поисковые запросы давали такие результатыВ итоге в мае сторы на поисковые запросы давали такие результаты

Apple ссылались на пункт 5.2.1 Apps should be submitted by the person or legal entity that owns or has licensed the intellectual property and other relevant rights.

Google блочил со ссылкой на пункт 8.3, в котором говорится, что компания не берет на себя отвественности за надзор за контентом приложений, но может заблочить, если решит, что содержимое что-нибудь нарушает.

Сейчас публикация приложений, связанных с ковид, разрешена в основном государственным организациям.

Хранение данных

Когда-то я работал в компании, которой прилетел реджект за то, что мы храним данные приложения в iCloud'е пользователя. Делали мы это не специально, а по не знанию) При этом, как оказалось, какие-то данные хранить в iCloud можно, но это должен быть сгенерированный пользователем контент.

Это самый первый пункт из iOS Data Storage Guidelines: "Only documents and other data that is user-generated, or that cannot otherwise be recreated by your application, should be stored in the <Application_Home>/Documents directory and will be automatically backed up by iCloud. "

Убрали хранение данных в локальный кеш и смогли пройти ревью.

Пермишены

В iOS 14.5 стал обязательным запрос нового пермишена - про трекинг данных пользователя. Компании принялись рассказывать юзерам на предварительных экранах почему же надо разрешить трекинг и... некоторые столкнулись с блокировками как раз из-за онбординг экрана для пермишена. Дело было в добавлении двух кнопок на этот экран. По нажатию одной - запрашивалось разрешение, второй - нет. В гайдланах это строчка "If you display a custom screen that precedes a privacy-related permission request, it must offer onlyoneaction, which must display the system alert."

При этом, например, у facebook'а получалось проходить ревью с двумя кнопками При этом, например, у facebook'а получалось проходить ревью с двумя кнопками Но позже и facebook, и instagram заменили эти экраны на однокнопочныеНо Но позже и facebook, и instagram заменили эти экраны на однокнопочныеНо

Ссылки на другие приложения

Когда я начинал разрабатывать свои приложения, то пользовался кросслинками из одного в другое. И так мои новые игры набирали лояльную аудиторию из старых. Довольно неплохо работало. Делал я это максимально примитивно - ставил иконку нового приложения в угол экрана меню старых. А еще на экране подтверждения закрытия приложения третьей кнопкой был переход в новую игру. Но через какое-то время Google начал поочередно блокировать одно приложение за другим, т.к. "Ads must not simulate the user interface of any app". Оказалось, что к подобным переходам надо явно писать, что они являются рекламой.

Слишком взрослый рейтинг

Напоследок совсем забавная для меня формулировка. Первая от Google. Приложения не пропускали в стор из-за того, что google play решил, что поставлен слишком высокий возрастной рейтинг. Сделано это, чтобы не заморачиваться с контентом, который мог где-нибудь(например, в рекламе) появиться, а детям его показывать не стоит. Но google сказал, что "We determine that some elements of your store listing may appeal to children under 13: Animated characters in app icon, young characters". Пришлось понижать возрастной рейтинг и фильтровать "опасные" категории рекламы.

А с какими блокировками приходилось сталкиваться вам?

Подробнее..

Из песочницы Alt City Online. Как я в одиночку создавал Gta Online для мобильных устройств. Часть 1

23.09.2020 02:13:19 | Автор: admin
Возможно ли в здравом уме замахнуться на подобный проект в одного, и надо ли оно вообще? Спойлер: да (длинный пост с картинками и видео).



Предыстория


Разработкой программных продуктов я занимаюсь уже 6 лет, начинал с разработки приложений для iOS. После выпуска нескольких приложений, которые в общей сумме принесли около $500, решил попробовать себя в разработке сайтов и настройке рекламы. В этой сфере я проработал 3 года, и понял, что создавать сайты не то, чем мне хотелось бы заниматься в жизни.

Так как с детства я очень любил игры, решил рассмотреть геймдев как будущую нишу, где хотел бы себя попробовать. Сделал бесплатную игру на SpriteKit (фреймворк Apple для создания 2D игр), начал знакомиться с инструментами для разработки игр. Решил подробно изучать Unity, так как он мне показался оптимальным вариантом для разработки именно мобильных игр. Выпустил в AppStore и в Google Play простенькую игру на Unity, и естественно поиграли в нее условно 3 с половиной человека. Это меня не особо остановило, так как цель разработки этой игры была в основном в том, чтобы познакомиться с процессом разработки в Unity и запуском игры именно в Google Play. Эти цели были выполнены, можно было двигаться дальше. Я начал уже более тщательно изучать Unity: 3-4 часа в день стабильно проходил Advanced курсы по разработке. Думаю, что мне повезло попался действительно подробный и толковый курс по созданию RPG в Unity, и многое, особенно различные best-practices, я узнал именно из него.

В это время мне подвернулась вакансия в одной крупной компании-разработчике мобильных игр, решил попробовать. Проработал там 3-4 месяца. Это была моя первая работа по найму. До этого вполне успешно работал только на себя. После определенного времени я понял, что это не мое. Надо отдать должное компания предоставляла максимальные удобства для работы. И вообще поразило то, насколько у нас в стране (живу в России, в городе миллионнике) может быть крутое отношение к работникам. Ни в коем случае не хочу сказать, что в других компаниях плохое отношение, просто то что я наблюдал это очень круто.

В общем, после ухода с работы, пришло понимание, что хочу попробовать создать действительно интересную и уникальную игру (наверное термин уникальная игра не совсем вяжется с концепцией игры-аналога GTA Online, но об этом дальше). С детства я обожал серию GTA играл десятками часов напролет в GTA Vice City и GTA San Andreas, ставил моды, крутил параметры машин. Потом после выхода GTA IV все то же самое делал с ней. Потом GTA IV: Episodes from Liberty City, GTA V. И естественно GTA Liberty City Stories, GTA Vice City Stories, GTA Chinatown Wars для PSP. Также было потрачено куча часов в других подобных играх Saints Row, Godfather 2 и т. д. Эх, хорошие были времена

Так вот, потом я познакомился уже с различными Role Play проектами, основанными на GTA. Но знакомство с ними, к сожалению, уже происходило через YouTube, так как работа стала занимать практически все время, а найти 30 минут в день на ролик не проблема. Считаю, что RP проекты создали очень интересную нишу, и вообще переосмыслили GTA.

RP проекты создали очень интересную нишу, и вообще переосмыслили GTA

Как я уже сказал выше, свободного времени становилось все меньше, и я захотел поиграть во что-то по типу GTA Online / GTA RP на телефоне благо сегодня телефоны действительно мощные, и по идее что-то подобное можно реализовать (например тот же PUBG, который отлично работает на практических любых устройствах). Каково было мое удивление, когда в AppStore я нашел буквально 3 игры, которые хоть как-то можно было отнести к аналогам GTA Online, да и те ужасные. Вот так и появилась идея создать первый аналог GTA Online для устройств на базе iOS и Android.

ALT: City Online




Геймплей в ALT: City Online это смесь классической GTA Online и ее Role Play модификаций. В самом начале игры ты появляешься в стартовой точке (предполагается, что это будет либо вокзал, либо аэропорт). Твоя задача найти работу и начать зарабатывать деньги и опыт. По мере получения опыта, тебе будут открываться новые профессии. Список профессий будет широкий, и я сейчас работаю над тем, чтобы сделать геймплей каждой профессии максимально интересным насколько это возможно. Далее ты сможешь купить себе квартиру, мотоцикл, потом дом, машину, машину получше в общем все, кто играли в GTA RP, знакомы с этим. Фишка игры заключается в том, что в сессии, в отличии от классической GTA Online, будут сотни человек, ты сможешь взаимодействовать со всеми разговаривать, наносить урон, кооперировать, обмениваться вещами, продавать вещи.



В игре будет возможность покупать оружие, менять его скины. Также в игре будет доступен тюнинг транспортных средств.

Но главное отличие от RP проектов в ALT: City Online нет классической для таких проектов консоли, нет администраторов, не нужно отыгрывать РП. Ты можешь, но не обязан.

Площадь карты в игре около 225 квадратных километров, но примерно треть площади покрыто водой, так что эффективная площадь равна примерно 150-160 квадратным километрам. Естественно, наполнить такой большой мир контентом в одиночку достаточно сложно, поэтому игра будет наполняться контентом в последующих обновлениях.



Важно то, что игра будет работать не только на последних топовых девайсах. Например, если говорить об iOS, то минимально поддерживаемое устройство iPhone 7. Вообще, основным боттлнеком оптимизации игры стала непрозрачность потребления памяти на iOS платформе (это известный недостаток Unity, с которым на данный момент мало что можно сделать), из-за чего было достаточно сложно оптимизировать огромный открытый мир для работы на маленьком устройстве с 2 гб оперативной памяти.


Какие вопросы предстояло решить


В первую очередь надо было вообще понять, возможно ли реализовать мобильную онлайн игру в большом открытом мире на Unity? Соответственно, был куплен простенький генератор города для Unity, контроллер персонажа, скачаны бесплатные модели оружия и автомобиля и кое-как настроен клиент сервер (вопрос реализации мультиплеера решался достаточно долго, так как официального решения от Unity нет, а фреймворков много, и они очень отличаются, расскажу о сетевой архитектуре подробнее в одной из будущих технических статей). Спустя две недели был готов достаточно играбельный прототип. То есть был запущен тестовый сервер игры на виртуальном сервере, установлены клиенты на телефоны друзей. Мы подключились, поиграли все отлично работает для прототипа, все довольны. Провел стресс тест, получилось, что минимум 100 игроков сервер точно держит. Для игры это достаточный минимум, но вообще, цель 600-1000 игроков на сервере (то есть столько игроков будет одновременно в сессии). В общем, пришло понимание, что Unity очень даже подходит под этот проект.


Самый главный вопрос был снят, можно было приступать к написанию диздока. Первая версия диздока была написана за неделю. Достаточно подробная, надо сказать. Подробнее о диздоке будет в одной из следующих статей.

Далее нужно было понять, как быть с 3D моделями? А их нужно было действительно много здания, автомобили, различные пропсы, одежда, оружие. И самое главное как смоделировать сам мир: ландшафт (террейн), дорожную сеть, город? Написал подробный список всех нужных объектов. Потратил неделю на поиск нужных моделей по списку, и понял, что в принципе все что нужно есть в магазинах 3D моделей.

Сделаю отступление надо понимать, что я занимаюсь проектом с декабря на фул-тайме (по 10-12 часов в день, без выходных), а практически все средства, отложенные за прошлые годы, я тратил на покупку различных инструментов и 3D моделей. Думаю, это снимет многие вопросы по поводу того, почему на некоторые этапы потрачено мало времени.

Все, что я написал выше, произошло в период с декабря прошлого года до февраля текущего. Начал работу над проектом в декабре, то есть за три месяца был протестирован прототип, написан диздок, найдены ресурсы для реализации идеи. Вопрос оставался за малым все это сделать и собрать в кучу.

Важно в самом начале, еще до написания диздока, думать о том, как игроки узнают о твоей будущей игре. Мой скромный опыт показывает, что самая лучшая маркетинговая стратегия это сделать действительно уникальную крутую игру. Если игра действительно уникальная и очень крутая, то у тебя нет варианта, чтобы игра провалилась. Да, я знаю, что очень многие готовы сильно поспорить с этим утверждением, что в игру надо вкачать много денег, чтобы она выстрелила, и т.д. Одно скажу я тоже раньше так думал. Но были обстоятельства, которые показали мне, что если игра крутая она выстрелит и без маркетинговых бюджетов, а если игра отстой то ее никакие бюджеты не спасут. Поэтому мой основной маркетинговый план был сделать интересный и уникальный проект.

Текущее состояние проекта


На данный момент я работаю над игрой уже девятый месяц. Проект готов к альфа релизу на 85%. Уже сейчас полностью смоделирована карта, настроена работа открытого мира на телефонах, проведена работа над рендерингом (LODы, различные настройки графики, оптимизация текстур, динамический батчинг и т.д.), настроена архитектура клиент-сервера, оптимизировано потребление памяти.

Для альфа релиза осталось доработать базовые механики, добавить работы, добавить контент (автомобили, одежду), добавить UI и все это хорошенько протестировать.


Скриншоты










Заключение


Спасибо, что дочитали данный пост до конца. Это мой первый опыт написания статьи, так что буду рад фидбеку. Это первая статья из цикла, посвященного скорому релиз игры ALT: City Online. Последняя статья этого цикла будет новостью о релизе игры. Так что, пожалуйста, пишите, про что хотели бы почитать в будущих постах.

Огромная просьба ко всем, кого заинтересовал проект: скоро мы начинаем открытые альфа тесты в онлайне на Android и iOS, поэтому вступайте в группу ВКонтакте, чтобы узнать, когда начнется альфа тестирование. Тем самым вы очень поможете развитию проекта. Всем тестировщикам естественно полагаются жирные игровые призы сразу после релиза проекта.

Также подписывайтесь на Twitter, там будут выкладываться новости, а также актуальные фото и видео о разработке: @AltCityOnline

На сайте ALT: City Online вы также можете оставить свой email. На него придет оповещение, когда игра будет доступна для загрузки. Всем, кто оставил свой email на сайте, так же положен жирный бонус при запуске игры!
Подробнее..

SafetyNet Attestation описание и реализация проверки на PHP

11.02.2021 20:09:20 | Автор: admin

В эту тему пришлось детально погрузиться во время работы над обеспечением стандартных механизмов верификации устройств для разных мобильных платформ. Задача сводилась к разработке полноценной реализацию проверки JWS-токенов по протоколу SafetyNet на серверной стороне.

После многочасовых поисков и скрупулёзного изучения официальной документации Google решил поделиться полученным опытом. Потому что, кроме официальной документации, я нашел только отрывочные описания частных примеров реализации на разных ЯП. И ни намека на комплексное объяснение особенностей проверки по SafetyNet на сервере.

Статья будет полезна разработчикам, которые хотят подробнее разобраться с технологией верификации устройств по протоколу SafetyNet Attestation. Для изучения описательной части не обязательно знать какой-либо язык программирования. Я сознательно убрал примеры кода, чтобы сфокусироваться именно на алгоритмах проверки. Сам пример реализации на PHP сформулирован в виде подключаемой через composer библиотеки и будет описан ниже.

Дисклеймер: материал в явном виде содержит перевод официальной документации от Google с разъяснениями и описанием особенностей реализации, с которыми я столкнулся.

О технологии

Технология SafetyNet Attestation разработана Google как средство предоставления разработчикам мобильных приложений информации о надёжности приложения клиента при взаимодействии с сервером, который обслуживает мобильное приложение. Для этого в протоколе взаимодействия предусмотрен удостоверяющий сервис от Google, обеспечивающий верификацию, и представлены рекомендации по проверке ответа от удостоверяющего центра на стороне сервера.

Google пишет, что данный метод проверки не может исключить все принятые на сегодняшний момент методы защиты и верификации устройств. То есть SafetyNet не представляет собой единственный механизм защиты от небезопасного трафика, а создавался как дополнительный инструмент.

Что позволяет проверить технология:

  1. Что именно вы являетесь автором приложения, которое сейчас взаимодействует с сервером.

  2. Что в процессе взаимодействия клиента и сервера нет больше никого, кроме вашего приложения и сервера.

  3. Что операционная система мобильного устройства не претерпела изменений, критичных для обеспечения безопасного обмена с сервером (не заручено не взломано, а также то, что устройство прошло аттестацию совместимости с Android).

В каких случаях механизм не применим или не имеет смысла:

  1. На устройстве пользователя отсутствует интернет, нет возможности связаться с удостоверяющим центром. В таком случае API выдаст ошибку на клиенте, и мы не сможем получить подписанный токен для проверки на сервере.

  2. Если попытаемся выполнить верификацию подписанного токена в самом мобильном приложении (без участия сервера), так как проверка клиента не должна происходить на клиенте. Если у вас приложение без Backend, или вы в принципе не планируете верификацию SafetyNet на серверной части приложения, то нет смысла устанавливать и настраивать этот механизм проверки.

  3. Если требуется детальное понимание статусов модификации системы, на которой работает мобильное приложение. В протокол заложен механизм однозначного определения модификации устройства. Он состоит из двух переменных: ctsProfileMatch и basicIntegrity. Об их назначении чуть ниже.

Остальные пункты в рамках этой статьи, на мой взгляд, менее интересны. Общий принцип такой: если вам нужно что-то очень точное или что-то, что обезопасит контент, ищите другой (дополнительный) способ защиты. Аналогично в случае, когда вы не собираетесь реализовывать проверку в нормальном порядке, как это задумано протоколом, или ваше приложение опирается на созданные уязвимости в конфигурации устройства.

Схематично процесс проверки клиента можно представить в виде схемы:

Рассмотрим поэтапно процесс верификации устройств по протоколу:

  1. Инициация процесса проверки со стороны клиента.Отправка запроса от клиента на Backend на генерацию уникального идентификатора проверки (nonce) сессии. В процессе выполнения запроса на сервере генерируется ключ (nonce) сессии, сохраняется и передаётся на клиент для последующей проверки.

  2. Генерация JSW-токена на стороне удостоверяющего центра.Клиент, получив nonce, отправляет его на удостоверяющий центр вместе со служебной информацией. Затем в качестве ответа клиенту возвращается JWS, содержащий информацию о клиенте, время генерации токена, информацию о приложении (хеши сертификатов, которыми подписывается приложение в процессе публикации в Google Store), информацию о том, чем был подписан ответ (сигнатуру). О JWS, его структуре и прочих подробностях расскажу дальше в статье.

  3. Затем клиент передаёт JWS в неизменном виде на Backend для проверки. А на стороне сервера формируется ответ с информацией о результате прохождения аттестации.После получения статуса проверки JWS на стороне сервера обычно сохраняют факт проверки и, опираясь на него, влияют на функциональность положительным или негативным образом. Например, клиентам, не прошедшим аттестацию, можно отключить возможность писать комментарии, голосовать за рейтинг, совершать иные активности, которые могут повлиять на качество контента приложения или создавать угрозу и неудобство другим пользователям.

Описание процесса верификации на стороне сервера JWS от удостоверяющего центра

Документация Google в рамках тестирования на сервере предлагает организовать online-механизм верификации JWS, при котором с сервера приложения отправляется запрос с JWS на удостоверяющий сервис Google. А в ответе от сервиса Google содержится полный результат проверки JWS.

Но данный метод проверки JWS для промышленного использования не рекомендуются. И даже больше: для каждого приложения существует ограничение в виде 10 000 запросов в сутки (подробнее об ограничениях здесь), после которых вы выгребите квоту и перестанете получать от него вменяемый ответ. Только информацию об ошибке.

Далее расскажу обо всём алгоритме верификации JWS, в том числе о верификации самих сертификатов (проверке цепочки сертификатов).

Подробнее о JWS

JWS представляет собой три текстовых (base64 зашифрованных) выражения, разделенные точками (header.body.signature):

Например:

eyJhbGciOiJSUzI1NiIsICJ4NWMiOiBbInZlcnlzZWN1cmVwdWJsaWNzZXJ0Y2hhaW4xIiwgInZlcnlzZWN1cmVwdWJsaWNzZXJ0Y2hhaW4yIl19.ewogICJub25jZSI6ICJ2ZXJ5c2VjdXJlbm91bmNlIiwKICAidGltZXN0YW1wTXMiOiAxNTM5ODg4NjUzNTAzLAogICJhcGtQYWNrYWdlTmFtZSI6ICJ2ZXJ5Lmdvb2QuYXBwIiwKICAiYXBrRGlnZXN0U2hhMjU2IjogInh5eHl4eXh5eHl4eXh5eHl5eHl4eXg9IiwKICAiY3RzUHJvZmlsZU1hdGNoIjogdHJ1ZSwKICAiYXBrQ2VydGlmaWNhdGVEaWdlc3RTaGEyNTYiOiBbCiAgICAieHl4eXh5eHl4eXh5eHl4eXh5eD09PT09Lz0iCiAgXSwKICAiYmFzaWNJbnRlZ3JpdHkiOiB0cnVlCn0=.c2lnbmF0dXJl

В данном примере после расшифровки base64 получим:

Header :

json_decode(base64_decode(eyJhbGciOiJSUzI1NiIsICJ4NWMiOiBbInZlcnlzZWN1cmVwdWJsaWNzZXJ0Y2hhaW4xIiwgInZlcnlzZWN1cmVwdWJsaWNzZXJ0Y2hhaW4yIl19))={"alg":"RS256","x5c":["verysecurepublicsertchain1","verysecurepublicsertchain2"]}

Body:

json_decode(base64_decode(ewogICJub25jZSI6ICJ2ZXJ5c2VjdXJlbm91bmNlIiwKICAidGltZXN0YW1wTXMiOiAxNTM5ODg4NjUzNTAzLAogICJhcGtQYWNrYWdlTmFtZSI6ICJ2ZXJ5Lmdvb2QuYXBwIiwKICAiYXBrRGlnZXN0U2hhMjU2IjogInh5eHl4eXh5eHl4eXh5eHl5eHl4eXg9IiwKICAiY3RzUHJvZmlsZU1hdGNoIjogdHJ1ZSwKICAiYXBrQ2VydGlmaWNhdGVEaWdlc3RTaGEyNTYiOiBbCiAgICAieHl4eXh5eHl4eXh5eHl4eXh5eD09PT09Lz0iCiAgXSwKICAiYmFzaWNJbnRlZ3JpdHkiOiB0cnVlCn0=))={"nonce":"verysecurenounce","timestampMs":1539888653503,"apkPackageName":"very.good.app","apkDigestSha256":"xyxyxyxyxyxyxyxyyxyxyx=","ctsProfileMatch":true,"apkCertificateDigestSha256":["xyxyxyxyxyxyxyxyxyx=====/="],"basicIntegrity":true}

Signature

json_decode(base64_decode(c2lnbmF0dXJl))= signature

Остановимся на том, что именно содержится во всем JWS.

Header:

  • alg алгоритм, которым зашифрованы Header и Body JWS. Нужен для проверки сигнатуры.

  • x5c публичная часть сертификата (или цепочка сертификатов). Также нужен для проверки сигнатуры.

Body:

  • nonce произвольная строка полученная с сервера и сохранённая на нём же.

  • timestampMs время начала аттестации.

  • apkPackageName название приложения, которое запросило аттестацию.

  • apkDigestSha256 хеш подписи приложения, которое загружено в Google Play.

  • ctsProfileMatch флаг, показывающий прошло ли устройство пользователя верификацию в системе безопасности Google (основной и самый жёсткий критерий, по которому можно понять было ли устройство заручено и прошло ли оно сертификацию в Google).

  • apkCertificateDigestSha256 хеш сертификата (цепочки сертификатов), которыми подписано приложение в Google Play.

  • basicIntegrity более мягкий (по сравнению с ctsProfileMatch) критерий целостности установки.

Signature

Бинарная сигнатура, с помощью которой можно сделать заключение, что тело сообщения JWS было подписано с использованием сертификатов (цепочки сертификатов) указанных в Header, и с использованием известного нам приватного ключа. Ключевое позволяет понять, что в цепочке взаимодействия нет никого, кроме нас и удостоверяющего центра Google.

Проверка сертификатов

Перейдём к непосредственной проверки каждой части полученного JWS. Начнём с сертификатов и алгоритма шифрования:

1. Проверяем, что алгоритм, с помощью которого подписано тело, нами поддерживается:

[$checkMethod, $algorithm] = JWT::$supported_algs[$statement->getHeader()->getAlgorithm()];if ($checkMethod != 'openssl') {   throw new CheckSignatureException('Not supported algorithm function');}

2. Проверяем, что сертификат (цепочка сертификатов), содержащиеся в Header (поле x5c), удовлетворяют нас по содержимому (загружаются в качестве публичных ключей):

private function extractAlgorithm(array $headers): string{   if (empty($headers['alg'])) {       throw new EmptyAlgorithmField('Empty alg field in headers');   }   return $headers['alg'];}private function extractCertificateChain(array $headers): X509{   if (empty($headers['x5c'])) {       throw new MissingCertificates('Missing certificates');   }   $x509 = new X509();   if ($x509->loadX509(array_shift($headers['x5c'])) === false) {       throw new CertificateLoadError('Failed to load certificate');   }   while ($textCertificate = array_shift($headers['x5c'])) {       if ($x509->loadCA($textCertificate) === false) {           throw new CertificateCALoadError('Failed to load certificate');       }   }   if ($x509->loadCA(RootGoogleCertService::rootCertificate()) === false) {       throw new RootCertificateError('Failed to load Root-CA certificate');   }   return $x509;}

3. Валидируем сигнатуру сертификата (цепочки сертификатов):

private function guardCertificateChain(StatementHeader $header): bool{   if (!$header->getCertificateChain()->validateSignature()) {       throw new CertificateChainError('Certificate chain signature is not valid');   }   return true;}

4. Сверяем hostname подписавшего сервера с сервером аттестации Google (ISSUINGHOSTNAME = 'attest.android.com'):

private function guardAttestHostname(StatementHeader $header): bool{   $commonNames = $header->getCertificateChain()->getDNProp('CN');   $issuingHostname = $commonNames[0] ?? null;   if ($issuingHostname !== self::ISSUING_HOSTNAME) {       throw new CertificateHostnameError(           'Certificate isn\'t issued for the hostname ' . self::ISSUING_HOSTNAME       );   }   return true;}

Верификация тела JWS

Самый значимым пункт для определения характеристик, участвующего в обмене устройства с приложением. Что нам нужно проверить на данном этапе:

1. Проверка nounce.

Тут все просто. Распаковали JWS, получили в Body nonce и сверили с тем, что у нас сохранено на сервере:

private function guardNonce(Nonce $nonce, StatementBody $statementBody): bool{   $statementNonce = $statementBody->getNonce();   if (!$statementNonce->isEqual($nonce)) {       throw new WrongNonce('Invalid nonce');   }   return true;}

2. Проверяем заручено ли устройство, с которого происходит запрос.

Тут нужно принять решение, на что вы будете опираться для закрытия того или иного функционала пользователей, не прошедших эту проверку.

Есть два параметра, на основе которых можно принимать решение о надежности устройства: ctsProfileMatch и basicIntegrity. ctsProfileMatch более строгий критерий, он определяет сертифицировано ли устройство в Google Play и верифицировано ли устройство в сервисе проверки безопасности Google. basicIntegrity определяет, что устройство не было скомпрометировано.

private function guardDeviceIsNotRooted(StatementBody $statementBody): bool{   $ctsProfileMatch = $statementBody->getCtsProfileMatch();   $basicIntegrity = $statementBody->getBasicIntegrity();   if (empty($ctsProfileMatch) || !$ctsProfileMatch) {       throw new ProfileMatchFieldError('Device is rooted');   }   if (empty($basicIntegrity) || !$basicIntegrity) {       throw new BasicIntegrityFieldError('Device can be rooted');   }   return true;}

3. Проверяем время начала прохождения аттестации.

Тоже ничего сложного. Нужно проверить, что с момента ответа от сервера Google прошло немного времени. По сути, нет чётких критериев прохождения теста с реферальным значением нужно определиться самим.

private function guardTimestamp(StatementBody $statementBody): bool{   $timestampDiff = $this->config->getTimeStampDiffInterval();   $timestampMs = $statementBody->getTimestampMs();   if (abs(microtime(true) * 1000 - $timestampMs) > $timestampDiff) {       throw new TimestampFieldError('TimestampMS and the current time is more than ' . $timestampDiff . ' MS');   }   return true;}

4. Проверяем подпись приложения.

Здесь тоже два параметра: apkDigestSha256 и apkCertificateDigestSha256. Но apkDigestSha256 самой Google помечен как нерекомендуемый способ проверки. С марта 2018 года они начали добавлять мета-информацию в приложения из-за чего ваш хеш подписи приложения может не сходиться с тем, который будет приходить в JWS (подробнее здесь).

Поэтому единственным способом проверки остается проверка хеша подписи приложения apkCertificateDigestSha256. Фактически этот параметр нужно сравнить с теми sha1 ключа, которым подписываете apk при загрузке в Google Play.

private function guardApkCertificateDigestSha256(StatementBody $statementBody): bool{   $apkCertificateDigestSha256 = $this->config->getApkCertificateDigestSha256();   $testApkCertificateDigestSha256 = $statementBody->getApkCertificateDigestSha256();   if (empty($testApkCertificateDigestSha256)) {       throw new ApkDigestShaError('Empty apkCertificateDigestSha256 field');   }   $configSha256 = [];   foreach ($apkCertificateDigestSha256 as $sha256) {       $configSha256[] = base64_encode(hex2bin($sha256));   }   foreach ($testApkCertificateDigestSha256 as $digestSha) {       if (in_array($digestSha, $configSha256)) {           return true;       }   }   throw new ApkDigestShaError('apkCertificateDigestSha256 is not valid');}

5. Проверяем имя приложения, запросившего аттестацию.

Сверяем название приложения в JWS с известным названием нашего приложения.

private function guardApkPackageName(StatementBody $statementBody): bool{   $apkPackageName = $this->config->getApkPackageName();   $testApkPackageName = $statementBody->getApkPackageName();   if (empty($testApkPackageName)) {       throw new ApkNameError('Empty apkPackageName field');   }   if (!in_array($testApkPackageName, $apkPackageName)) {       throw new ApkNameError('apkPackageName ' . $testApkPackageName. ' not equal ' . join(", ", $apkPackageName));   }   return true;}

Верификация сигнатуры

Здесь нужно совершить одно действие, которое даст нам понимание того, что Header и Body ответа JWS подписаны сервером авторизации Google. Для этого в исходном виде склеиваем Header c Body (с разделителем в виде ".") и проверяем сигнатуру:

protected function guardSignature(Statement $statement): bool{   $jwsHeaders = $statement->getRawHeaders();   $jwsBody = $statement->getRawBody();   $signData = $jwsHeaders . '.' . $jwsBody;   $stringPublicKey = (string)$statement->getHeader()->getCertificateChain()->getPublicKey();   [$checkMethod, $algorithm] = JWT::$supported_algs[$statement->getHeader()->getAlgorithm()];   if ($checkMethod != 'openssl') {       throw new CheckSignatureException('Not supported algorithm function');   }   if (openssl_verify($signData, $statement->getSignature(), $stringPublicKey, $algorithm) < 1) {       throw new CheckSignatureException('Signature is invalid');   }   return true;}

Вместо заключения. Библиотека на PHP

Уже после решения задачи и отдельно от нашей кодовой базы, я разработал библиотеку на PHP, которая обеспечивает полный цикл верификации JWS.

Её можно скачать из Packagist и использовать в своих прое

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru