Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

React Native Androidはなぜ動くのか

6,235 views

Published on

DroidKaigi 2018で講演したやつです

Published in: Technology
  • Be the first to comment

React Native Androidはなぜ動くのか

  1. 1. React Native Android 2018.2.9 DroidKaigi 2018 Yukiya Nakagawa / @Nkzn Room2 12:50-13:40 #droidkaigi_room2
  2. 2. Who are you? • Yukiya Nakagawa / @Nkzn • @ • • Android 2009 • React Native v0.17
  3. 3. React Native
  4. 4. • • Hello World • Production
  5. 5. Target • React Native 
 Android • Android React Native
  6. 6. Best Match • • JavaScript • React Native
  7. 7. Agenda
  8. 8. Overview
  9. 9. React
  10. 10. React is
  11. 11. React 2017
  12. 12. React https://facebook.github.io/react/
  13. 13. • • JSX • Reactive
  14. 14. JSX
  15. 15. <div> <Header /> <LeftPane /> <RightPane name={myName}/> </div>
  16. 16. React
  17. 17. import React from 'react'; import ReactDOM from 'react-dom'; const styles = { container: {display: 'flex', flexDirection: ‘row', …} }; class App extends React.Component { render() { const myName = /* props or state */; return ( <div style={styles.container}> <Header /> <LeftPane /> <RightPane name={myName} /> </div> ); } } ReactDOM.render( <App />, document.getElementById('app') );
  18. 18. Virtual DOM
  19. 19. <ccc style={{ width: 200, color: "red" }} enabled={true} />
  20. 20. React VirtualDOM DOM
  21. 21. React VirtualDOM DOM
  22. 22. React VirtualDOM DOM
  23. 23. React VirtualDOM DOM
  24. 24. https://tylermcginnis.com/an-introduction-to-life-cycle-events-in-react-js/
  25. 25. https://developer.android.com/reference/android/app/Activity.html
  26. 26. React is • Facebook JS • https://facebook.github.io/react/ • • • View View View
  27. 27. React Native React
  28. 28. import React from 'react'; import ReactDOM from 'react-dom'; const styles = { container: {display: 'flex', flexDirection: ‘row', …} }; class App extends React.Component { render() { const myName = /* props or state */; return ( <div style={styles.container}> <Header /> <LeftPane /> <RightPane name={myName} /> </div> ); } } ReactDOM.render( <App />, document.getElementById('app') ); import ReactDOM from 'react-dom'; div div ReactDOM.render( <App />, document.getElementById('app') );
  29. 29. import React from "react"; import { View, AppRegistry } from "react-native"; const styles = { container: {display: 'flex', flexDirection: ‘row', …} }; class App extends React.Component { render() { const myName = /* props or state */; return ( <View style={styles.container}> <Header /> <LeftPane /> <RightPane name={myName} /> </View> ); } } AppRegistry.registerComponent( "MyReactNativeApp", () => App );
  30. 30. React ReactDOM
  31. 31. React UI React Native
  32. 32. React is not
  33. 33. React • React DOM • React View Web • React Native • React View UI
  34. 34. React • View props • • • DOM • UI • • View • UI GUI Virtual DOM
  35. 35. React React DOM 

  36. 36. React is not • React • React View • React View
  37. 37. React Native Android
  38. 38. React Native
  39. 39. React Native • JavaScript • JS Java • React Android View •
  40. 40. Activity ReactRootView (FrameLayout) JS
  41. 41. Activity ReactRootView JS
  42. 42. Activity ReactRootView JS
  43. 43. Activity ReactRootView JS
  44. 44. JavaScript
  45. 45. Activity ReactRootView JS
  46. 46. JS • JavaScriptCore • WebKit(Safari) JS • Facebook Android NDK 
 https://github.com/facebook/android-jsc
  47. 47. • ReactRootView God FrameLayout • ReactInstanceManager JS • CatalystInstance JNI
  48. 48. • ReactInstanceManager • JSC • JS • CatalystInstance • JNI Java • Java JSC IF startReactApplication() JS
  49. 49. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModulePath("index") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); mReactRootView.startReactApplication( mReactInstanceManager, "MyReactNativeApp", null); setContentView(mReactRootView); } Java Activity RN
  50. 50. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModulePath("index") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); mReactRootView.startReactApplication( mReactInstanceManager, "MyReactNativeApp", null); setContentView(mReactRootView); } Java ReactRootView FrameLayout
  51. 51. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModulePath("index") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); mReactRootView.startReactApplication( mReactInstanceManager, "MyReactNativeApp", null); setContentView(mReactRootView); } Java ReactInstanceManager
  52. 52. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModulePath("index") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); mReactRootView.startReactApplication( mReactInstanceManager, "MyReactNativeApp", null); setContentView(mReactRootView); } Java RootView InstanceManager
  53. 53. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mReactRootView = new ReactRootView(this); mReactInstanceManager = ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModulePath("index") .addPackage(new MainReactPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); mReactRootView.startReactApplication( mReactInstanceManager, "MyReactNativeApp", null); setContentView(mReactRootView); } Java setContentView
  54. 54. import React from "react"; import { View, AppRegistry } from "react-native"; const styles = { container: {display: 'flex', flexDirection: ‘row', …} }; class App extends React.Component { render() { const myName = /* props or state */; return ( <View style={styles.container}> <Header /> <LeftPane /> <RightPane name={myName} /> </View> ); } } AppRegistry.registerComponent( "MyReactNativeApp", () => App ); MyReactNativeApp
  55. 55. ReactInstance • React JS Java • React React
  56. 56. JSC JS ReactInstanceManager ↑ View ReactRootView ReactRootView#startReactApplication() Java JavaScript
  57. 57. NDK
  58. 58. JS Java
  59. 59. Activity ReactRootView JS
  60. 60. Native Modules
  61. 61. Native Modules • Java Swift JS • RN Android Java JS •
  62. 62. Native Modules 3
  63. 63. const ToastAndroid = require('ToastAndroid'); ToastAndroid.show(" ", ToastAndroid.SHORT); JS Toast JS
  64. 64. @ReactModule(name = "ToastAndroid") public class ToastModule extends ReactContextBaseJavaModule { @ReactMethod public void show(final String message, final int duration) { UiThreadUtil.runOnUiThread(() -> { Toast.makeText( getReactApplicationContext(), message, duration).show(); }); } } Toast Java
  65. 65. @ReactModule(name = "ToastAndroid") public class ToastModule extends ReactContextBaseJavaModule { @ReactMethod public void show(final String message, final int duration) { UiThreadUtil.runOnUiThread(() -> { Toast.makeText( getReactApplicationContext(), message, duration).show(); }); } } ReactContextBaseJavaModule Java
  66. 66. @ReactModule(name = "ToastAndroid") public class ToastModule extends ReactContextBaseJavaModule { @ReactMethod public void show(final String message, final int duration) { UiThreadUtil.runOnUiThread(() -> { Toast.makeText( getReactApplicationContext(), message, duration).show(); }); } } Native Module Java ※name
  67. 67. @ReactModule(name = "ToastAndroid") public class ToastModule extends ReactContextBaseJavaModule { @ReactMethod public void show(final String message, final int duration) { UiThreadUtil.runOnUiThread(() -> { Toast.makeText( getReactApplicationContext(), message, duration).show(); }); } } JS @ReactMethod Java
  68. 68. @ReactModule(name = "ToastAndroid") public class ToastModule extends ReactContextBaseJavaModule { @ReactMethod public void show(final String message, final int duration) { UiThreadUtil.runOnUiThread(() -> { Toast.makeText( getReactApplicationContext(), message, duration).show(); }); } } Android not UI Thread Java
  69. 69. ReactInstanceManager JS
  70. 70. public class ToastPackage implements ReactPackage { @Override public List<ViewManager> createViewManagers( ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) { return Arrays.<NativeModule>asList( new ToastModule(reactContext)); } } ReactPackage Java
  71. 71. public class ToastPackage implements ReactPackage { @Override public List<ViewManager> createViewManagers( ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) { return Arrays.<NativeModule>asList( new ToastModule(reactContext)); } } ReactPackage Java
  72. 72. public class ToastPackage implements ReactPackage { @Override public List<ViewManager> createViewManagers( ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) { return Arrays.<NativeModule>asList( new ToastModule(reactContext)); } } createNativeModules Java
  73. 73. ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModulePath("index") .addPackage(new MainReactPackage()) .addPackage(new ToastPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); ReactInstanceManager Java
  74. 74. ReactInstanceManager.builder() .setApplication(getApplication()) .setBundleAssetName("index.android.bundle") .setJSMainModulePath("index") .addPackage(new MainReactPackage()) .addPackage(new ToastPackage()) .setUseDeveloperSupport(BuildConfig.DEBUG) .setInitialLifecycleState(LifecycleState.RESUMED) .build(); Java
  75. 75. ReactInstanceManager JSC JS
  76. 76. const ToastAndroid = require('ToastAndroid'); ToastAndroid.show(" ", ToastAndroid.SHORT); JavaScript JS
  77. 77. Great!
  78. 78. @ReactMethod
  79. 79. Readable/Writable Map/Array • JS Java/C++
  80. 80. + hasKey(name: String): boolean + isNull(name: String): boolean + getBoolean(name: String): boolean + getDouble(name: String): double + getInt(name: String): int + getString(name: String): String + getArray(name: String): ReadableArray + getMap(name: String): ReadableMap + getDynamic(name: String): Dynamic + getType(name: String): ReadableType + keySetIterator(): ReadableMapKeySetIterator + toHashMap(): HashMap<String, Object> + putNull(key: String) + putBoolean(key: String, value: boolean) + putDouble(key: String, value: double) + putInt(key: String, value: int) + putString(key: String, value: String) + putArray(key: String, value: WritableArray) + putMap(key: String, value: WritableMap) + merge(source: ReadableMap);
  81. 81. + size(index: int): int + isNull(index: int): boolean + getBoolean(index: int): boolean + getDouble(index: int): double + getInt(index: int): int + getString(index: int): String + getArray(index: int): ReadableArray + getMap(index: int): ReadableMap + getDynamic(index: int): Dynamic + getType(index: int): ReadableType + toArrayList(index: int): ArrayList<Object> + pushNull() + pushBoolean(value: boolean) + pushDouble(value: double) + pushInt(value: int) + pushString(value: String) + pushArray(array: WritableArray) + pushMap(map: WritableMap)
  82. 82. JSC++Java { name: "nkzn", age: 30 } [ "cupcake", "donut", "eclair" ]
  83. 83. Promise
  84. 84. Promise • ReactMethod Promise JS Promise • promise.resolve() promise.reject() JS
  85. 85. @ReactMethod public void getString(Promise promise) { try { ClipboardManager clipboard = getClipboardService(); ClipData clipData = clipboard.getPrimaryClip(); if (clipData == null) { promise.resolve(""); } else if (clipData.getItemCount() >= 1) { ClipData.Item firstItem = clipboard .getPrimaryClip() .getItemAt(0); promise.resolve("" + firstItem.getText()); } else { promise.resolve(""); } } catch (Exception e) { promise.reject(e); } } Clipboard#getString Java
  86. 86. @ReactMethod public void getString(Promise promise) { try { ClipboardManager clipboard = getClipboardService(); ClipData clipData = clipboard.getPrimaryClip(); if (clipData == null) { promise.resolve(""); } else if (clipData.getItemCount() >= 1) { ClipData.Item firstItem = clipboard .getPrimaryClip() .getItemAt(0); promise.resolve("" + firstItem.getText()); } else { promise.resolve(""); } } catch (Exception e) { promise.reject(e); } } JS RxJava onNext, onError ※ Clipboard Java
  87. 87. // Promise Style Clipboard.getString() .then(str => { // use string }); // async/await Style async function getClip() { const str = await Clipboard.getString(); return str; } JS JS
  88. 88. Java JS
  89. 89. EventEmitter Android Broadcast
  90. 90. // JS class RCTDeviceEventEmitter extends EventEmitter { emit(eventType) {...} addListener(eventType, listener, context) {...} removeAllListeners(eventType) {...} removeSubscription(subscription) {...} } JS RCTDeviceEventEmitter.js ※ emit EventEmitter
  91. 91. // interface // ReactInstanceModule public interface RCTDeviceEventEmitter extends JavaScriptModule { void emit(String eventName, @Nullable Object data); } Java DeviceEventManagerModule.java
  92. 92. // JS public void emitHardwareBackPressed() { getReactApplicationContext() .getJSModule(RCTDeviceEventEmitter.class) .emit("hardwareBackPress", null); } JS emit Java DeviceEventManagerModule.java
  93. 93. C++
  94. 94. JS→Java ReactModule Java→JS JavaScriptModule
  95. 95. ReactModule React 🤔
  96. 96. React Android 
 View
  97. 97. Activity ReactRootView JS
  98. 98. React DOM Android
  99. 99. Android View React
  100. 100. Native UI Components 3
  101. 101. public class PhotoView extends ImageView { public PhotoView(Context context) { ... } // Android } Java
  102. 102. public class PhotoViewManager extends SimpleViewManager<PhotoView> { @Override public String getName() { return "PhotoView"; } @Override protected PhotoView createViewInstance( ThemedReactContext reactContext) { return new PhotoView(reactContext); } @ReactProp(name = "uri") public void setUri(PhotoView view, @Nullable String uri) { view.setUri(uri); } } React Java
  103. 103. public class PhotoViewManager extends SimpleViewManager<PhotoView> { @Override public String getName() { return "PhotoView"; } @Override protected PhotoView createViewInstance( ThemedReactContext reactContext) { return new PhotoView(reactContext); } @ReactProp(name = "uri") public void setUri(PhotoView view, @Nullable String uri) { view.setUri(uri); } } SimpleViewManager Java
  104. 104. public class PhotoViewManager extends SimpleViewManager<PhotoView> { @Override public String getName() { return "PhotoView"; } @Override protected PhotoView createViewInstance( ThemedReactContext reactContext) { return new PhotoView(reactContext); } @ReactProp(name = "uri") public void setUri(PhotoView view, @Nullable String uri) { view.setUri(uri); } } React Java
  105. 105. public class PhotoViewManager extends SimpleViewManager<PhotoView> { @Override public String getName() { return "PhotoView"; } @Override protected PhotoView createViewInstance( ThemedReactContext reactContext) { return new PhotoView(reactContext); } @ReactProp(name = "uri") public void setUri(PhotoView view, @Nullable String uri) { view.setUri(uri); } } Android View Java
  106. 106. public class PhotoViewManager extends SimpleViewManager<PhotoView> { @Override public String getName() { return "PhotoView"; } @Override protected PhotoView createViewInstance( ThemedReactContext reactContext) { return new PhotoView(reactContext); } @ReactProp(name = "uri") public void setUri(PhotoView view, @Nullable String uri) { view.setUri(uri); } } props Java
  107. 107. // @ReactProp(name = "uri") public void setUri(PhotoView view, @Nullable String uri) { view.setUri(uri); } // <PhotoView uri="http://example.com/hoge.png" /> Java JS
  108. 108. public class MyLibraryPackage implements ReactPackage { @Override public List<ViewManager> createViewManagers( ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new PhotoViewManager() ); } @Override public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) { return Collections.emptyList(); } } ReactPackage Java
  109. 109. public class MyLibraryPackage implements ReactPackage { @Override public List<ViewManager> createViewManagers( ReactApplicationContext reactContext) { return Arrays.<ViewManager>asList( new PhotoViewManager() ); } @Override public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) { return Collections.emptyList(); } } createViewManagers Java
  110. 110. ReactInstanceManager Native Modules
  111. 111. import PropTypes from “prop-types”; import { requireNativeComponent, View } from "react-native"; const name = "PhotoView"; const photoViewInterface = { name: name, displayName: name, propTypes: { ...View.propTypes, uri: PropTypes.string.isRequired } }; export default requireNativeComponent(name, photoViewInterface); JS PhotoView.js JS Java Java
  112. 112. import PhotoView from "./PhotoView"; // <PhotoView uri="http://example.com/hoge.png" /> JS
  113. 113. • JS UI props interface • ViewManager
  114. 114. React Android View
  115. 115. Native Module UIManagerModule
  116. 116. UIManagerModule • React React Native React DOM Java • createView updateView ReactMethod
  117. 117. @ReactMethod public void createView( int tag, String className, int rootViewTag, ReadableMap props) { mUIImplementation.createView( tag, className, rootViewTag, props); } @ReactMethod public void updateView( int tag, String className, ReadableMap props) { mUIImplementation.updateView( tag, className, props); } UIManagerModule.java
  118. 118. React ReactMethod
  119. 119. View • React View Java ReactShadowNode Java View Yoga • UIManagerModule React Java View • View View
  120. 120. Yoga https://facebook.github.io/yoga/
  121. 121. • Flexbox Yoga Android • borderColor ViewManager Android setBorderColor
  122. 122. React
  123. 123. • Java C++ JS • ReactInstanceManager • ReactInstanceManager Native Module JavaScript Module • UI Native Module
  124. 124. React Native Modules
  125. 125. Android
  126. 126. • Android APK • APK
  127. 127. Application Sources import $buildDir/intermediates /assets/release /res/merged/release
  128. 128. iOS require("path/to/awesome.png")
  129. 129. iOS
  130. 130. React Native Android • API View Android • • JS JS
  131. 131. • Android SDK iOS SDK • Web • JS
  132. 132. • React Native 
 http://tomoima525.hatenablog.com/entry/2017/12/19/180523 • Android 
 7 
 https://peaks.cc/Nkzn/architecture_patterns @tomoaki_imai

×