Не занимаясь никогда ранее нативной разработкой под мобильные платформы, и в этот раз решил пойти "легким путем" — освоить React Native. Наибольшей трудностью стало добавление иконки приложения(AppIcon) и экрана загрузки (Launch Screen). О чем и хочу рассказать в данной статье тем, кто осваивает React Native.


На момент написания статьи актуальная версия React Native 41.0, XCode 8.2 (эти данные указаны по той причине, что в более поздних версиях может что-то измениться и данный мануал не будет применим).


Начнем...


Создаем React Native приложение


react-native init habr

Добавление AppIcon


На iOS


Идем в папку с iOS-частью приложения


cd habr/ios/

и открываем там файл XCode-проекта habr.xcodeproj.


Далее, щелкаем по следующим кнопкам:




В поле 4 добавляем иконки путем перетаскивания их в пустые ячейки. Под ячейками указан размер иконки(в pt).


Получается примерно так:




Важно: картинка иконки должна быть квадратная и, в идеале, их должно быть несколько версий разного размера(под каждую ячейку — свой размер). Если не охота возиться с созданием иконок разного размера — добавьте одну, размером 120x120px, в ячейку для iPhone 7-10:



Если добавить иконки не правильного размера, то получите ошибку "Images.xcassets: The app icon set named “AppIcon” did not have any applicable content."


Полезно знать: иконки для ios удобнее всего создавать в программе Sketch(доступна только под OS X), поскольку в ней есть шаблоны нужных размеров, которые затем можно экспортировать в png-формат (File > Export...):




Запускаем сборку ios-версии из корневой папки проекта:


react-native run-ios

Получаем профит:



(hit: для "сворачивания" приложения в эмуляторе нужно дважды нажать Cmd+Shift+H)


На Android


Из папки проекта идем в папку с Android-частью приложения, в место хранения ресурсов:


cd habr/android/app/src/main/res/

и видим здесь папки:




Заходим в каждую из них и в каждой видим файл ic_launcher.png. Заменяем каждый файл на свой, с таким же именем и такого же размера (в px).


Запускаем сборку Android-версии из корневой папки проекта:


react-native run-android

Получаем профит:



С иконками закончили, переходим к экрану загрузки.


Добавление LaunchScreen


На iOS


Существует по крайней мере 2 способа добавить LaunchScreen на iOS. Опишу тот, который сработал у меня.


Первым делом, идем снова в XCode, по тому же маршруту, который показан на самом первом изображении в этой статье, но вместо папки Images.xcassets, выбираем файл LaunchScreen.xib.


При этом XCode спросит, для какой версии какого устройства отобразить содержимое данного файла. Выбираем любой iPhone.


Далее, щелкаем по кнопкам под номером 3 и 4 на данном скриншоте:




Затем перетаскиваем элемент 5 (Image View) на рабочее поле 6. Имеющиеся в рабочем поле 6 элементы (текстовые надписи) можно удалить.


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


Далее, щелкаем по элементу UIImageView в рабочей зоне и настраиваем его свойства:




В меню под номером 1 (на скриншоте) выбираем добавленную в предыдущем шаге картинку(если выпадающий список пуст, то щелкните в левой панели(там где выбирали файл LaunchScreen.xib по любому другому файлу, а затем снова вернитесь к файлу LaunchScreen.xib — файл появится в выпадающем списке. Это мелкий баг XCode).


В меню под номером 2 выберите "Aspect Fit", чтобы картинка масштабировалась пропорционально, независимо от размера экрана устройства, на котором будет запущено приложение.


Чтобы картинка располагалась строго по центру, щелкните самой картинке(на рабочей области) и нажмите на кнопку 1, как показано на следующем скриншоте:




В каждом из четырех полей "Add new constrains" установите значение 0.


Запускаем сборку ios-версии из корневой папки проекта:


react-native run-ios

Получаем профит:



На Android


Из папки проекта идем в папку с Android-частью приложения, в место хранения ресурсов:


cd habr/android/app/src/main/res/

Добавляем здесь папку drawable. Создаем в ней файл splash_screen.xml такого содержания


<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

   <item>
     <color android:color="@color/white"/>
   </item>

    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/ic_launcher"/>
    </item>
</layer-list>

Этот файл описывает новый "ресурс" приложения, и путь к внешним файлам ресурса(в нашем случае — к файлу с изображением для стартового экрана).


android:gravity="center"

эта часть кода указывает расположение ресурса на экране. А эта:


android:src="@drawable/ic_launcher"/>

путь к файлу ресурса, относительно папки res.


Блок кода


<item>
    <color android:color="@color/white"/>
</item>

Создает фоновую подложку к экрану загрузки, а строка


@color/white

указывает цвет фона. Значение цвета фона берется из файла colors.xml, который пока не существует и который вам нужно создать и расположить по адресу:


*


habr/android/app/src/main/res/values/colors.xml

Содержимое файла может быть таким:


<?xml version="1.0" encoding="utf-8"?>
<resources>
 <color name="orange">#ff5500</color>
 <color name="white">#ffffff</color>
 <color name="transparent">#00000000</color>
</resources>

Здесь каждая строчка вроде


 <color name="white">#ffffff</color>

содержит цветовую константу. Задать цветовое значение фона напрямую(в файле splash_screen.xml) мне не удалось, поэтому добавил такой файл, как советовалось в одной из инструкций в Сети.


Далее, в папку drawable добавляем файл ic_launcher.png, представляющий собой изображение на стартовом экране.


Затем идем в папку


cd habr/android/app/src/main/res/values

и редактируем файл styles.xml так, чтобы он выглядел следующим образом


<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
    </style>

    <!-- здесь мы добавляем свою часть кода -->
    <style name="SplashTheme" parent="AppTheme">
        <item name="android:windowBackground">@drawable/splash_screen</item>
    </style>

</resources>

Этим действием мы добавляем новую "тему оформления" для "активности"(activity).


"Активность"(Activity) в Android-приложениях представляет собой "экран" или "страницу". По умолчанию в React Native есть лишь одна "активность", мы же добавляем ещё одну.


Для этого переходим в папку с java-кодом:


cd habr/android/app/src/main/java/com/habr

(путь после /java/ в вашем проекте будет другим) и делаем следующее:


  1. переименовываем MainActivity.java в MainActivity2.java
  2. редактируем файл MainActivity2.java — меняем название класса в 6 строке с "MainActivity" на "MainActivity2":
    public class MainActivity2 extends ReactActivity {
  3. Создаем файл MainActivity.java, в который пишем такой код:


    package com.habr;//здесь вы указываете название вашего пакета
    import android.content.Intent;
    import android.os.Bundle;
    import com.facebook.react.ReactActivity;
    public class MainActivity extends ReactActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        Intent intent = new Intent(this, MainActivity2.class);
        startActivity(intent);
        finish();
    }
    }


Смысл перечисленных выше 3-х шагов прост: мы меняем стартовый загрузочный экран("активность") на наш экран("активность) SplashScreen.


(В этом абзаце вы могли заметить, что LaunchScreen переименовался в SplashScreen. В Android-разработке(и не только) принято называть загрузочный экран SplashScreen'ом.)


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


Открываем файл AndroidManifest.xml, который находится по адресу


/android/app/src/main/AndroidManifest.xml

(относительно корневой директории проекта)


И приводим его к такому виду:


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.habr"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="22" />

    <application
      android:name=".MainApplication"
      android:allowBackup="true"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:theme="@style/AppTheme">

      <!-- эта "активность" - добавленный нами экран загрузки -->
      <activity
          android:name=".MainActivity"
          android:theme="@style/SplashTheme">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
      </activity>

      <!-- эта "активность" - основной экран приложения -->
      <activity
        android:name=".MainActivity2"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
      </activity>

      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

В итоге, в файле AndroidManifest.xml мы имеем 2 активности, причем в одной из них указано, что именно она — та, с которой начнется запуск Android-приложения. Это делается добавлением таких параметров:


 <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>

в тело "активности".


С приготовлениями закончено. Запускаем билд android-версии из корневой папки проекта:


react-native run-android

Получаем профит:




Полный код проекта можно найти здесь.

Поделиться с друзьями
-->

Комментарии (13)


  1. drakmail
    27.02.2017 08:44

    Для иконок есть еще сервис makeappicon.com, через который можно сразу сделать иконки всех размеров


  1. storoj
    27.02.2017 11:44
    -1

    а при чем тут React Native?


  1. zagayevskiy
    27.02.2017 14:45

    Отвратительно. Да, самый нормальный способ сделать сплэш на андроиде — через бэкграунд в теме. Но. Зачем тут вторая активити? Это принесет вам баги. Просто надо занулять этот бэкграунд (getWindow().setBackgroundDrawable(null);) в onCreate activity, чтобы не было overdraw (лишнего слоя отрисовки).
    Про иконки вообще не понял. Кто-то может этого не знать? о_О Пусть прочтёт документацию.


    1. frog
      27.02.2017 15:21
      -1

      Человек пишет, как сделать это в рамках React Native. А вы предлагаете написать код на Java?


      1. zagayevskiy
        28.02.2017 15:00

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


        1. frog
          01.03.2017 15:46

          Вы правы, невнимательно смотрел.


    1. redflasher
      27.02.2017 20:28

      Как бы вы написали код для сплэша в андроиде?(если можно — пришлите рабочий пример, я внесу правки в статью)

      Важный нюанс — разработчики на React Native совсем не обязательно знакомы с нативной разработкой под Android и iOS.
      То есть, хотелось бы, в идеале, copy&paste-решение(поскольку не всем понравится мысль что надо изучать Android Development ради того, чтобы более правильно добавлять сплеш-скрин).


      1. zagayevskiy
        28.02.2017 15:03

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


        1. redflasher
          01.03.2017 00:07

          Да, я видел ваш код. Просто сам на Java последний раз лет 10 назад кодил(J2ME еще). Боюсь допустить неточность, самостоятельно внося правки в код статьи.
          Подумал, что вы захотите прислать свое видение кода MainActivity.java.
          А так да, наверняка еще вернусь к этому вопросу, и тогда разберусь с этим. Спасибо за подсказку!


          1. zagayevskiy
            01.03.2017 08:09

            А чей же тогда код на джаве в статье?


            1. redflasher
              01.03.2017 14:46

              stackoverflow


              1. zagayevskiy
                01.03.2017 15:35

                То есть вы скопипастили код, не разобрались в нём и ещё сляпали статью на хабр? Не зря я вам минус в карму влепил.


                1. redflasher
                  01.03.2017 16:58

                  Это не совсем так. Однако продолжать с вами дискуссию я более не намерен.