首先我們必須認知到我們雖應該盡量的共用程式碼,但不應該完全被綁死,由於 iOS、Android 功能實作上的限制、UI 的慣例都還是有其差異,Facebook 內部在使用 React Native 時共用程度大約是 87 % 左右,所以我們也必須了解這些差異以及實作的方式。
Building the F8 2016 App: Part 2 - Designing an App for Multiple Platforms 這篇文有詳細的描述 Facebook F8 App 的跨平台設計過程,很值得一讀。
裡面有提到幾個很明顯的差異,如下圖:
在設計 Menu 時,iOS 比較常放在下方:
其他比較明顯的差異有:
更多設計的差異,建議直接參閱平台官方的 Guideline:
React Native Packager 有內建的機制來處理不同平台的副檔名 (File Extension),例如我們一建立專案時所會看到的 index.ios.js
、index.android.js
,就相當於 iOS、Android 上面各自的 index.js
,這會在打包時處理妥當。
而其他的地方也可以類推:
const filename = require('./filename');
如果沒有 ./filename.js
、./filename.json
這些檔案,在 iOS 上會去找 ./filename.ios.js
、在 Android 上則會去找 ./filename.android.js
。
我們也一樣能使用副檔名來載入不同圖片,例如:my-icon.ios.png
and my-icon.android.png
。
另外,最新推出的 React VR,它的進入點則是 index.vr.js
,可以看出類似的模式。
React Native 的 Platform 模組,上面有一些關於平台的 Property 或是 Method 能夠取用。
其中這邊最有用的是 Platform.OS
,可以藉由判斷它的值是 ios
還是 android
來做不一樣的樣式或是邏輯:
import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
height: (Platform.OS === 'ios') ? 200 : 100,
});
實際的案例,可以看看 f8app 裡面的 F8SegmentedControl 中間的用法。
在 F8App 的介紹文 中有提到一個 F8StyleSheet.create
的用法,可以簡單地去指定平台相關的樣式:
/* from js/common/F8SegmentedControl.js */
var styles = F8StyleSheet.create({
container: {
flexDirection: 'row',
backgroundColor: 'transparent',
ios: {
paddingBottom: 6,
justifyContent: 'center',
alignItems: 'center',
},
android: {
paddingLeft: 60,
},
},
// ..
};
它的原始碼其實相當簡單,只是使用前面介紹過的 Platform.OS
來做屬性的覆寫:
export function create(styles: Object): {[name: string]: number} {
const platformStyles = {};
Object.keys(styles).forEach((name) => {
let {ios, android, ...style} = {...styles[name]};
if (ios && Platform.OS === 'ios') {
style = {...style, ...ios};
}
if (android && Platform.OS === 'android') {
style = {...style, ...android};
}
platformStyles[name] = style;
});
return StyleSheet.create(platformStyles);
}
有人把它抽出成獨立的 npm 套件 react-native-platform-stylesheet,讓我們可以直接安裝使用。
React Native 有提供橋接原生模組的方式,包括 Objective-C、Swift 的 iOS Module、Java 的 Android Module,如果有既有適合的原生程式模組,也是可以考慮直接利用這個方式來使用。
做出好的體驗是我們所共同追求的目標,除了未來 React Native 可能會幫我們處理妥善的部份以外,還需要盡己所能的去了解各平台的樣貌,以求能提供細緻的平台體驗。