fayeah / blogs

方法论、问题驱动、总结
6 stars 0 forks source link

【RN】如何给APP添加App Icon和Launch Screen(iOS&Andoid) #39

Open fayeah opened 4 years ago

fayeah commented 4 years ago

只加App Icon是比较简单的,但是Launch Screen有点麻烦,期间也遇到了许许多多的问题,但是最终也都解决了。

Environment:

nodejs:v12.4.0 React Native: 0.63.3 react-native-cli: 2.0.1 iOS simulator: iPhone 11-13.3 Andoid emulator: Pixel_XL_API_29(Google APIs Intel Atom (x86))

添加App Icon

iOS

  1. 准备一张1024x1024的图片,然后去这里生成iOS的各种尺寸的图标:

image

  1. 用xcode打开需要添加icon的项目,如果是RN的 项目,请打开子目录ios
  2. 找到Images.xcassets -> AppIcon,把之前生成好的图标按照大小一次拖拽到不同的区域:

image

  1. 重新build ios的包:npx react-native run-ios,iOS的图标就加好啦

image

Android

  1. 将同样的1024x1024的原图,拖拽到这里,生成不同大小的图片:

image

  1. 到Android的目录下面会看到有这么一个目录层级:app -> src -> main -> res,跟以上生成的目录一致,将图片放入对应的目录下即可:

image

  1. 同时也需要将ic_launcher_round.png(默认的android图标)也替换成我们需要的图标:

image

  1. 重新 build android的包,就可以看到我们新的图标了: npx react-native run-android

添加Launch Screen

iOS

  1. 使用xcode打开需要添加的project,找到LaunchScreen.storyboard,选中View Controller,再选中右侧的Show the Attributes Inspector,将Size这个选项设置为Page Sheet(Show the Attributes Inspector的第一个选项):

image

  1. 删掉默认的文本,默认是项目工程的名字,我这里是“mobileNew”;

  2. 添加Launch的图片,依然是到Images.xcassets,底部有一个加号,选择import,将准备好的图片添加进来:

image

  1. 回到LaunchScreen.storyboard,添加一个ImageView,先找到右上角的加号然后搜索ImageView,即可添加:

image

  1. 选中该ImageView,还是在Show the Attributes Inspector里面的第一个选项Image,选中下拉框里面刚刚添加好的Launch 图片;Content Mode选择 Aspect Fit

  2. 使图片居中:点击Show the Attributes Inspector旁边的Show The Size Inspector,将AutoResizing设置成以下,反选上左的线以及选中中间的线:

image

  1. 重新build 包,即可看到添加的Launch Screen,但是这里有一个问题,在Launch Screen和Main Screen中间会有一个白屏,我们后面跟Android一起解释如何解决。

Android

  1. 准备图片,到这里根据Launch 图标生成不同大小的图标(这里要注意大小,因为我后面设置的尺寸高宽一致,所以最好是正方形),一次放入到对应的目录里面,还是在res -> mipmap-*目录里面。

  2. 创建文件 background_splash.xml,在目录 android/app/src/main/res/drawable里面,添加代码内容:

    
    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    
    <item
        android:drawable="@color/blue"/>
    
    <item
        android:width="200dp"
        android:height="200dp"
        android:drawable="@mipmap/icon"
        android:gravity="center" />


3. 需要设置以下颜色,那么在目录`android/app/src/main/res/values`下面创建文件 `color.xml`:
```xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="blue">#4F6D7A</color>
    <color name="primary_dark">#4F6D7A</color>
</resources>
  1. android/app/src/main/res/values/styles.xml里面添加一个splash theme

    
    <resources>
    
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="android:statusBarColor">@color/blue</item>
    </style>
    
    <style name="SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@drawable/background_splash</item>
        <item name="android:statusBarColor">@color/blue</item>
    </style>


5. 告知app,在初始化的时候使用**splash theme**,在文件 `AndroidManifest.xml`里面添加`SplashActivity`:
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.mobilenew">

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

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".SplashActivity"
        android:theme="@style/SplashTheme"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

这里要注意的是

  1. 创建SplashActivity.java文件,与 MainActivity.java同一个目录:
    
    package com.mobilenew; // make sure this is your package name

import android.content.Intent; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity;

public class SplashActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

    Intent intent = new Intent(this, MainActivity.class);
    startActivity(intent);
    finish();
}

}


7. 重新build ,就可以看到我们新加的Launch Screen了:

![splash_screen_with_white_background](https://github.com/fayeah/blogs/blob/master/assets/splash_screen_with_white_background.gif?raw=true)

跟iOS一样,都会有一个**白屏**的问题。

## 解决白屏问题
上面的Launch Screen不论iOS还是Android都有一个白屏的问题需要解决,那么解决方式是引入第三方依赖`react-native-splash-screen`。

### iOS

1. 添加依赖 `yarn add react-native-splash-screen`,link `react-native link react-native-splash-screen`。但是这里无法link 成功,显示以下**error**: `Cannot read property 'match' of undefined`,解决办法是删掉node_modules目录,重新安装依赖: `yarn install`。(参考:https://github.com/facebook/react-native/issues/16774)

2. 在 `app.js` 里面添加useEffect hook,告知splash screen,一旦app准备好之后隐藏它:

import SplashScreen from 'react-native-splash-screen';

... const App: () => React$Node = () => { useEffect(() => { SplashScreen.hide(); }, []);

return (...


2. 当重新build ios的时候依然有以下错误:

![image](https://user-images.githubusercontent.com/29644978/94982884-c1c01880-0570-11eb-9308-4c383b0b193d.png)

意思是,虽然已经link了,但是对于ios来说依然需要进入到**ios**目录下面,去安装依赖 `pod install`。

3. 使用xcode打开ios工程,找到 `AppDelegate.m`,添加依赖RNSplashScreen:`#import <RNSplashScreen.h>`,并且在`didFinishLaunchingWithOptions`方法里面添加 `[RNSplashScreen show];`,就在`return YES` 的前面一行:

```swift
  [self.window makeKeyAndVisible];
  [RNSplashScreen show];
  return YES;
  1. 当重新build ios的时发生以下错误:

image

虽然也安装, 也link了,但是还是找不到该依赖,解决办法就是 添加路径到相应的配置里面:

选中 项目→ Build Settings → Search Paths → Header Search Paths 添加:

$(SRCROOT)/../node_modules/react-native-splash-screen/ios

  1. 重新build ios,即可看到修复白屏的结果。

Android

在link成功之后Android基本上依赖是加好了,重复iOS的 step 1- step 2

  1. 然后,在 MainActivity.java 里面重写onCreate方法:

    import org.devio.rn.splashscreen.SplashScreen;
    import android.os.Bundle;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        SplashScreen.show(this);  // here
        super.onCreate(savedInstanceState);
    }
  2. 需要在android/app/src/main/res/layout目录下创建一个文件 launch_screen.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/blue"
    android:gravity="center">
    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginTop="24dp"
        android:src="@mipmap/icon"
    />
    </LinearLayout>
  3. 重新build android的包,就就可以看到白屏修复之后的效果了:

android_splash_screen_final

中间遇到的一些问题

  1. 最开始如果忘记添加图片到正确的目录下:

image

  1. 使用androidx.appcompat.app.AppCompatActivity而不是android.support.v7.app.AppCompatActivity,在参考文章中用的依赖不适合我这的情况,所以我需要在SplashActivity.java文件里面引用正确的依赖androidx.appcompat.app.AppCompatActivityimage

References:

Note:

安装完一个新的依赖之后,会报一些错误,可能需要删掉simulator上的app,重新start和install。 router doc: https://reactnavigation.org/docs/getting-started/