通過第一部分開發 React Native APP —— 從改造官方 Demo 開始(一)介紹,App 框架基本構建完成,這部分主要討論 UI/交互、App 發佈前的準備工做及如何發佈,具體內容包括:html
完整 demo 在這 react-native-complete-demojava
這裏的擴展指的是實現可單獨配置頁面的進入方式(react navigation 默認只支持全局配置,要麼 card
,要麼 modal
,配置後全部頁面進入動畫相同)。react
實現上述效果須要作兩方面修改:StackNavigator
API(在 route.js
中使用)和進入某個頁面是的調用方式。android
StackNavigator
API修改後若是使頁面默認狀態爲 card,只須要輸入對應頁面便可,好比 ..navigate('ScreenSome1')
;若是要使某個頁面進入方式爲 modal 只須要在路徑上加上 Modal 好比:..navigate('ScreenSome2Modal')
。ios
須要注意的是若是頁面進入方式爲 modal,須要自定義 header,由於默認 header 樣式失效,都疊在一塊了。git
/** * route.js * 自定義 StackNavigator,能夠選擇 screen 進入方式 */ const StackModalNavigator = (routeConfigs, navigatorConfig) => { const CardStackNavigator = StackNavigator(routeConfigs, navigatorConfig); const modalRouteConfig = {}; const routeNames = Object.keys(routeConfigs); for (let i = 0; i < routeNames.length; i++) { modalRouteConfig[`${routeNames[i]}Modal`] = routeConfigs[routeNames[i]]; } const ModalStackNavigator = StackNavigator( { CardStackNavigator: { screen: CardStackNavigator }, ...modalRouteConfig }, { // 若是頁面進入方式爲 modal,須要自定義 header(默認 header 樣式失效,都疊在一塊了) mode: "modal", headerMode: "none" } ); return ModalStackNavigator; }; // 設置路由 const AppNavigator = StackModalNavigator();
首先咱們新建頁面 ScreenSome2
,接下來就讓它以 modal 的形式進入(從屏幕下面進入),做爲對比 ScreenSome1
以 card
的形式進入(默認進入方式,從屏幕右側進入)。github
由於以 modal 形式進入的頁面須要自定義 header,通常只是一個關閉按鈕,以 ScreenSome2
爲例:segmentfault
/** * ScreenSome2/view.js * 自定義 header(關閉按鈕) */ <View> {/* TouchableHighlight 爲關閉按鈕的熱區 */} <TouchableHighlight onPress={() => self.navigation.goBack()} underlayColor="transparent" style={{ display: "flex", justifyContent: "center", marginTop: pxToDp(30), width: pxToDp(150), height: pxToDp(90), backgroundColor: "yellow" }} > <Text style={{ marginLeft: pxToDp(24) }}>關閉</Text> </TouchableHighlight> <Text style={{ fontSize: pxToDp(36) }}>some2,以 modal 的形式進入</Text> </View>
而後就是更改進入 ScreenSome2
代碼,這裏是 ScreenHome
頁面中的代碼:react-native
/** * ScreenHome/view.js * 自定義 header(關閉按鈕) */ { /* ScreenSome2 從屏幕右側進入 */ } <Button title="goSome1" onPress={() => self.navigation.navigate("ScreenSome1")} />; { /* ScreenSome2 從屏幕下面進入 */ } <Button title="goSome2Modal" onPress={() => self.navigation.navigate("ScreenSome2Modal")} />;
最終效果圖:
android-studio
自適應主要包括兩方面:尺寸根據屏幕大小自適應,包括 fontSize
,width
等;圖片分辨率根據屏幕分辨率自適應,也就常說的二倍圖、三倍圖等。
尺寸自適應的原理是經過獲取手機屏幕的寬度,尺寸作相應比例的調整,爲此封裝了一個工具函數,放在了 config/pxToDp.js
中。
調整後的目錄以下:
config/pxToDp.js
尺寸轉換的工具函數尺寸轉換的工具函數在第一部分 開發 React Native APP —— 從改造官方 Demo 開始(一)已經添加
1)編寫自適應尺寸工具函數
由於全部涉及尺寸的數據都要轉換(fontSize
,width
等),因此對轉換後的數據要作處理,保證:1.大於等於 1 的數字向上取整;2.小於 1 的數字,若是是 ios 平臺統一設爲 0.5;若是是安卓平臺統一設爲 1(由於安卓平臺分辨率千差萬別萬別,低分辨率的屏幕顯示 0.5 的尺寸會有鋸齒狀)。工具函數完整代碼以下:
/** * pxToDp.js * 自適應佈局 * @param uiElementPx: ui給的原始尺寸 */ import { Dimensions, Platform } from "react-native"; // app 只有豎屏模式,因此能夠只獲取一次 width const deviceWidthDp = Dimensions.get("window").width; // UI 默認給圖是 750 const uiWidthPx = 750; function pxToDp(uiElementPx) { const transferNumb = uiElementPx * deviceWidthDp / uiWidthPx; if (transferNumb >= 1) { // 避免出現循環小數 return Math.ceil(transferNumb); } else if (Platform.OS === "android") { // 若是是安卓,最小爲1,避免邊框出現鋸齒 return 1; } return 0.5; } export default pxToDp;
實際上,經過Dimensions.get('window').width
獲取的屏幕寬度和本身想象的可能有出入,好比,iphone7 屏幕 4.7'',獲取到的寬度是375
,華爲 P9 是 5.2',但獲取到的寬度倒是是360
!有點坑,這個工具函數還有待優化。
2)使用自適應尺寸工具函數
使用方法很簡單,在須要轉換單位的組件中將轉換尺寸的工具函數引入,將須要轉換的尺寸傳入工具函數便可,以 ScreenHome
爲例:
/** * ScreenHome/view.js */ // 引入尺寸轉換工具函數 import pxToDp from "../../config/pxToDp"; // 將須要轉換的單位傳入 pxToDp 中 <Text style={{ fontSize: pxToDp(36) }}>home</Text>;
手機分辨率愈來愈多,尤爲安卓,React Native 能夠根據不一樣分辨率加載不一樣尺寸的圖片,只需在圖片命名上面加以區分。
好比咱們有張圖片叫 test.png
,尺寸爲 40 x 40
(單位像素),爲了作到自適應屏幕分辨率,咱們還須要提供它的 2 倍圖,3 倍圖,這樣,一張圖片就對應 3 個尺寸,以下:
# 一張圖片提供 3個尺寸 test.png # 尺寸 40 x 40 test@2x.png # 尺寸 80 x 80 test@3x.png # 尺寸 120 x 120
name@nx
是 n (n > 1) 倍圖命名規範,React Native 也是根據命名判斷圖片尺寸的。
在引用圖片的時候直接使用 不加倍率後綴的圖片名,好比,直接使用 test.png
,以下:
/** * ScreenTab3/view.js */ <Image source={require("../../assets/images/test.png")} style={{ height: pxToDp(80), width: pxToDp(80) }} />
最終效果圖以下:
2X
字樣)3X
字樣)
修改桌面圖標、App 展現名稱相對簡單,設置啓動頁稍微麻煩。另外,iOS 修改桌面圖標、App 展現名稱,設置啓動頁都須要在 Xcode 中進行。
由於 App 圖標對應多個尺寸,手動改寫太麻煩,這個網站能夠自動生成 MakeAppIcon。
並非全部尺寸的圖片都須要,見下文。
準確點講不能叫設置桌面圖標,而應該是 App 圖標,由於咱們須要設置的不止有桌面展現的圖標,還有設置時 app 圖標、消息推送時 app 圖標,此外若是要發佈到 App store,還須要設置 Apple Store 展現用的 App 圖標。
1)圖片準備
以上不一樣地方用到的 app 圖標尺寸各不相同,具體以下(只針對 iphone,不包括 ipad,iwatch):
尺寸 | 名稱 | 用途 | 是否必須 |
---|---|---|---|
120x120 | Icon-60@2x.png | 桌面圖標 (2x) | 必須 |
180x180 | Icon-60@3x.png | 桌面圖標 (3x) | 可選,但推薦設置 |
80x80 | Icon-40@2x.png | Spotlight 圖標 (2x) | 可選,但推薦設置 |
120x120 | Icon-40@3x.png | Spotlight 圖標 (3x) | 可選,但推薦設置 |
58x58 | Icon-29@2x.png | 設置圖標 (2x) | 可選,但推薦設置 |
87x87 | Icon-29@3x.png | 設置圖標 (3x) | 可選,但推薦設置 |
40x40 | Icon-20@2x.png | 通知圖標 (3x) | 可選,但推薦設置 |
80x80 | Icon-20@3x.png | 通知圖標 (3x) | 可選,但推薦設置 |
1024x1024 | iTunesArtwork@2x.png | App Store (2x) | 必須 |
名稱不是說必定要和上面相同,但Icon
、尺寸(如60
)還有倍率(@nx)要有,類型爲png
。
2)將圖片拖放至 Xcode 指定位置,具體是:Project Navigator -> Images.xcassets -> AppIcon
,以下圖
拖放完成後,經過文件管理器查看項目目錄,也會發現相應圖片。
安卓的 app 圖標相對簡單,只須要設置桌面圖標。設置位置在 yourApp/android/app/src/main/res/
目錄下,這個目錄默認有四個文件夾,裏面各對應放置了一種尺寸的桌面圖標圖片,圖片尺寸不一樣,但名稱相同,統一爲 ic_launcher.png
,具體以下所示:
文件夾名稱 | 含義 | 文件夾內部圖片尺寸 | 文件夾內部圖片名稱 |
---|---|---|---|
mipmap-ldpi | Low Density Screen | 36x36 | ic_launcher.png |
mipmap-mdpi | Medium Density Screen | 48x48 | ic_launcher.png |
mipmap-hdpi | High Density Screen | 72x72 | ic_launcher.png |
mipmap-xhdpi | Extra-high density screen | 96x96 | ic_launcher.png |
mipmap-xxhdpi | xx-high density screen | 144x144 | ic_launcher.png |
mipmap-xxxhdpi | xxx-high density screen | 192x192 | ic_launcher.png |
若是你使用了 MakeAppIcon 的服務,直接將對應文件夾所有放入 res/
目錄下就好,否則就手動替換圖標。
能夠根據實際需求刪除沒必要要的文件,好比,120 DPI 的屏幕不多了,那麼這個文件夾就能夠不要
調出工程設置菜單(雙擊工程名稱或者單擊而後而後右側選擇 Targets --> yourProject),進入 info
選項,在 Custom iOS Target Properties
中添加 Bundle display name
,其 value
即是 App 的名稱。具體設置以下圖:
安卓修改 App 展現名稱在這個文件中 yourApp/android/app/src/main/res/values/strings.xml
。
strings.xml
這個文件很簡單,所有內容以下:
<resources> <string name="app_name">你的app名稱</string> </resources>
替換 你的app名稱
爲你想要的名字就好。
NOTE:
安卓的話,還要修改默認包名(applicationId
),若是不修改,若是系統監測到當前應用的 applicationId
和已安裝的某個應用相同而簽名不一樣,會報錯:「簽名不一致 該應用可能已被惡意篡改」。
在這個文件中修改包名: yourApp/android/app/build.gradle
:
// ... defaultConfig { applicationId "com.yourAppId" // ... } // ...
這裏使用了第三方插件react-native-splash-screen,官網教程已經很詳細,這裏作簡要介紹。
1)下載依賴
yarn add react-native-splash-screen
2)添加到項目中
react-native link react-native-splash-screen
3)在 React Native 配置
這裏指的是設置啓動頁何時消失,下面的代碼是首頁加載完 5s 後啓動頁消失。
/** * ScreenHome/index.js * 設置啓動頁消失時間 */ import SplashScreen from "react-native-splash-screen"; // 引入 react-native-splash-screen export default class ScreenHome extends Component { // ...other code componentDidMount() { // 隱藏啓動頁,若是不設置消失時間,在組件加載完啓動頁自動隱藏 setTimeout(() => { SplashScreen.hide(); }, 5000); } // ...other code }
1)更新 AppDelegate.m
:
#import <React/RCTBundleURLProvider.h> #import <React/RCTRootView.h> #import "SplashScreen.h" // 導入啓動頁插件 @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ...其餘代碼 [self.window makeKeyAndVisible]; [SplashScreen show]; // 顯示啓動頁 return YES; } @end
2)準備啓動頁圖片
文件必須是 png 格式的圖片,命名需對應尺寸,可參考下面的命名:
如需自動生成可以使用這個網頁: appicon
尺寸 | 名稱 | 用途 | 是否必須 |
---|---|---|---|
640 x 960 | Default@2x.png | iPhone 4 | 非必須,推薦設置 |
640 x 1136 | Default-568h@2x.png | iPhone 5 | 非必須,推薦設置 |
750 x 1334 | Default-667h@2x.png | iPhone 6, 豎屏 | 必須(必須有至少一個啓動頁圖片) |
1242 x 2208 | Default-736h@3x.png | iPhone 6 Plus, 豎屏 | 非必須,推薦設置 |
2208 x 1242 | Default-Landscape-736h@3x.png | iPhone 6 Plus, 橫屏 | 非必須,推薦設置 |
1125 × 2436 | Default-812h@3x.png | iPhone X, 豎屏 | 非必須,推薦設置 |
2436 x 1125 | Default-Landscape-812h@3x.png | iPhone X, 橫屏 | 非必須,推薦設置 |
NOTE:
Default尺寸x尺寸.png
也能夠;3)在 Xcode 中設置啓動頁
首先新建 LaunchImage
文件,操做步驟以下:
而後在 general
設置中將啓動頁指向剛纔新建的 LaunchImage
文件,注意 Launch Screen File 必須爲空,否則就指向 LaunchScreen.xib 中默認的啓動頁了:
1)更新 MainActivity.java
:
import android.os.Bundle; // here import com.facebook.react.ReactActivity; // react-native-splash-screen >= 0.3.1 import org.devio.rn.splashscreen.SplashScreen; // here // react-native-splash-screen < 0.3.1 import com.cboy.rn.splashscreen.SplashScreen; // here public class MainActivity extends ReactActivity { @Override protected void onCreate(Bundle savedInstanceState) { SplashScreen.show(this); // here super.onCreate(savedInstanceState); } // ...other code }
2)新建 launch_screen.xml
在 app/src/main/res/layout
中建立 launch_screen.xml
(若是沒有 layout
目錄,新建),內容以下:
<?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="@drawable/launch_screen"> </LinearLayout>
3)準備不一樣尺寸的啓動頁圖片並放到項目中
安卓是經過文件夾路徑尋找啓動頁面的,因此,多張尺寸的啓動頁名稱相同,都爲 launch_screen.png
,但要放在不一樣文件夾中,文件夾放置目錄爲 yourApp/android/app/src/main/res/
,名稱及對應放置的圖片尺寸以下:
文件夾名稱 | 含義 | 文件夾內部圖片尺寸 | 文件夾內部圖片名稱 |
---|---|---|---|
drawable-ldpi | Low Density Screen | 240x320 | launch_screen.png |
drawable-mdpi | Medium Density Screen | 320x480 | launch_screen.png |
drawable-hdpi | High Density Screen | 480x800 | launch_screen.png |
drawable-xhdpi | Extra-high density screen | 720x1280 | launch_screen.png |
drawable-xxhdpi | xx-high density screen | 960x1600 | launch_screen.png |
drawable-xxxhdpi | xxx-high density screen | 1280x1920 | launch_screen.png |
建議直接從
480x800
起步放置 4 張圖片就好。
4)優化啓動頁出現前的短暫白屏
到這裏,啓動頁功能已經 ok,但若是仔細看,能夠看到啓動頁出現前會有短暫白屏,此時可經過更改android/app/src/main/res/values/styles.xml
解決:
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <!--設置透明背景--> <item name="android:windowIsTranslucent">true</item> </style> </resources>
這種方案實際沒有根本解決問題:會發現這樣設置之後點擊圖片不能當即彈出應用,而有短暫的等待時間,待填坑。
5)解決安卓 6.0,7.0 安裝配置完成後出現閃退,參考下面設置:
在 android/app/src/main/res/values
下面新建 colors.xml
文件,內容以下:
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- this is referenced by react-native-splash-screen and will throw an error if not defined. its value does nothing, just here to avoid a runtime error. --> <color name="primary_dark">#000000</color> </resources>
由於 react-native-splash-screen 須要一個名爲 primary_dark
的顏色值做爲狀態欄的顏色。
設置完桌面圖標、修改 APP 展現名稱及設置啓動頁以後的效果圖以下:
keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
若是使用 mac,執行該命令的目錄隨意。但必定要保管好本身的 my-release-key.keystore
文件,若是忘記簽名,不能在原有 App 上面升級,只能從新打包發佈。同時,不要將 keystore
文件放入版本控制中。
1)首先將簽名文件 my-release-key.keystore
放在目錄 yourApp/android/app/
下
2)修改文件 yourApp/android/gradle.properties
添加下面代碼 (替換 *****
爲正確的 keystore 密碼、別名、和 key 密碼):
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore MYAPP_RELEASE_KEY_ALIAS=my-key-alias MYAPP_RELEASE_STORE_PASSWORD=***** MYAPP_RELEASE_KEY_PASSWORD=*****
3)添加簽名信息到 app 的 gradle 配置中
編輯文件 yourApp/android/app/build.gradle
加入簽名信息
android { ... defaultConfig { ... } signingConfigs { release { if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) { storeFile file(MYAPP_RELEASE_STORE_FILE) storePassword MYAPP_RELEASE_STORE_PASSWORD keyAlias MYAPP_RELEASE_KEY_ALIAS keyPassword MYAPP_RELEASE_KEY_PASSWORD } } } buildTypes { release { ... signingConfig signingConfigs.release } } }
在終端輸入下面命令
cd android && ./gradlew assembleRelease
等待構建完成,即可以在 yourApp/android/app/build/outputs/apk/release/app-release.apk
中找到編譯後的發佈版本。
NOTE:若是遇到這個錯誤:Execution failed for task ':app:processReleaseResources'
,作下述修改:
在 yourApp/android/gradle.properties
文件最後添加下面代碼:
classpath 'com.android.tools.build:gradle:3.0.0' distributionUrl=https://services.gradle.org/distributions/gradle-4.1-all.zip android.enableAapt2=false
若是還有其餘問題,可參考下這篇文章:安卓打包發佈那些坑
iOS 打包發佈有些麻煩,對於大多數非 iOS 開發者的限制不是 React Native 自己,而是蘋果自己的機制,好比,必需要有蘋果開發者帳號。iOS 打包發佈打算另寫文章。若是要了解發布流程,能夠參考這兩篇文章:iOS 發佈 App Store 詳細圖文教程,React Native iOS 詳細打包步驟
注意一點:打包時--entry-file
安卓、iOS 是同一個入口文件index.js
,不在區分安卓/iOS
到目前位置,從改造官方 demo 開始,一個比較完整的 React Native App 完成了,在此基礎上能夠不斷擴展完善。
固然,從生產角度來講,這個 demo 的完成度不高,好比,不少樣式仍是最原始的狀態、好比 WebView(App 中嵌入 H5)、下拉刷新等也沒有涉及。其中 WebView、下拉刷新等經常使用功能會逐步集成到這個 demo 中,但樣式並不打算作過多優化,由於從使用角度來說,樣式的完成度越高意味着可定製性越差,而且,那樣也會致使代碼的可讀性變差。但願這個 demo 能夠成爲完整、普適但不臃腫的腳手架。
不過,同一套代碼,安卓和 iOS 上展現的樣式會有不一樣,針對這個,會寫文章單獨說明。
Choose transition mode for each screen in StackNavigator
React Native 開發適配心得
Apple Developer - App Icon
在模擬器安卓 4.0 上運行正常,在手機上安卓 6.0 7.0 都閃退 不知道什麼狀況求解
Issues with resources generated by react in Android Studio 3
React Native 的默認單位和自適應佈局方案