Upgrade to Pro — share decks privately, control downloads, hide ads and more …

discussion about the bridge

januswel
January 26, 2017

discussion about the bridge

discussion about the bridge of React Native

januswel

January 26, 2017
Tweet

More Decks by januswel

Other Decks in Programming

Transcript

  1. DISCUSSION ABOUT THE BRIDGE
    2017/01/26 React Native Meetup #4
    by januswel

    View Slide

  2. SPEAKER
    janus_wel
    [email protected]
    have developed on native
    iOS/Android
    janus_wel
    januswel

    View Slide

  3. CUREAPP, INC
    ΞϓϦͰපؾΛ
    ࣏ྍ͢ΔະདྷΛ
    ૑଄͢Δ

    View Slide

  4. FOR NASH
    PATIENT
    MADE WITH
    REACT NATIVE
    now, not available for the public

    View Slide

  5. OVERVIEW
    What is the bridge?
    What is native modules?
    Why the bridge is needed?
    advantages for users
    advantages for developers
    scripting native with React
    How does the bridge work?
    collecting native modules
    calling native functions
    calling JavaScript functions
    back

    View Slide

  6. OVERVIEW
    What is the bridge?
    What is native modules?
    Why the bridge is needed?
    advantages for users
    advantages for developers
    scripting native with React
    How does the bridge work?
    collecting native modules
    calling native functions
    calling JavaScript functions
    back

    View Slide

  7. WHAT IS THE BRIDGE?
    connector between JavaScript and native worlds
    collecting native modules
    loading bundled JavaScript
    calling native functions and calling JavaScript functions back

    View Slide

  8. WHAT IS NATIVE MODULES?
    modules implemented in native
    platforms
    to use platform-specific
    features
    to process heavy tasks with
    multi-thread
    React Native have lots of native
    modules and theirs bindings
    bridge
    native
    module
    native
    module
    native
    module

    bundled JavaScript

    View Slide

  9. OVERVIEW
    What is the bridge?
    What is native modules?
    Why the bridge is needed?
    advantages for users
    advantages for developers
    scripting native with React
    How does the bridge work?
    collecting native modules
    calling native functions
    calling JavaScript functions
    back

    View Slide

  10. ADVANTAGES FOR USERS
    It's possible to reimplement these components on the web, but
    our reimplementations never feel exactly like their native
    counterparts, and they also don't get updated automatically with
    changes to the platform
    https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/
    Why native is necessary
    Native behaviors
    help users to work
    with your app
    Apache Cordova
    reimplements
    components

    View Slide

  11. ADVANTAGES FOR DEVELOPERS
    it's harder to lay things out on the screen, and we often have to
    manually compute the size and position of all our views
    https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/
    On native, however, we need to recompile after every change,
    even if we just want to shift text a few pixels over on the
    screen.
    Why native is difficult
    Appcelerator
    Titanium needs
    recompile

    View Slide

  12. SCRIPTING NATIVE IS TRICKY
    our UI thread could end up being blocked on JavaScript
    execution. To make this efficient, we know we want to execute
    our JavaScript off the main thread, but doing so is hard.
    The first reason it's hard is resource contention.
    The second reason this is tough is that there's some fixed
    amount of overhead associated with every round trip between
    the native environment and the JavaScript virtual machine.
    https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/
    Scripting native is tricky

    View Slide

  13. SCRIPTING NATIVE IS TRICKY
    We need to fundamentally change the programming model
    and ensure that our system always passes messages across the
    thread boundary asynchronously and that we can batch up as
    many of these messages per frame as possible, minimizing
    cross-thread communication overhead.
    https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/
    Scripting native is tricky
    In order to this
    goal, the bridge is
    needed!!

    View Slide

  14. (REACT PROGRAMMING MODEL)
    Luckily, React gives us the perfect programming model to do
    this correctly.
    Since React components are just pure, side-effect-free functions
    that return what our views look like at any point in time, we
    never need to read from our underlying rendered view
    implementation in order to write to it.
    https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/
    Introducing React Native

    View Slide

  15. OVERVIEW
    What is the bridge?
    What is native modules?
    Why the bridge is needed?
    advantages for users
    advantages for developers
    scripting native with React
    How does the bridge work?
    collecting native modules
    calling native functions
    calling JavaScript functions
    back

    View Slide

  16. 1. loading bundled JavaScript
    source
    2. setting JavaScript executor
    up
    3. collecting native modules
    HOW DOES THE BRIDGE WORK?
    AppDelegate
    RCTRootView
    : UIView
    RCTBridge
    : NSObject
    RCTBatchedBridge
    : RCTBridge
    * AppDelegate: implementations about app lifecycle
    * UIView: base class for all views
    * NSObject: base class for all objects
    * RCT: abbr. ReaCT

    View Slide

  17. #import "RCTBridgeModule.h"
    @interface CalendarManager : NSObject
    @end
    @implementation CalendarManager
    RCT_EXPORT_MODULE()
    RCT_EXPORT_METHOD(addEvent:(NSString *)name at:(NSString *)location) {
    RCTLogInfo(@"Create an event: %@ at %@", name, location);
    }
    RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback) {
    NSArray *events = @[@"talk in 21cafe", @"write slides"];
    callback(@[[NSNull null], events]);
    }
    @end
    NATIVE MODULE EXAMPLE

    View Slide

  18. @interface, @implementation?
    https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/
    DefiningClasses/DefiningClasses.html
    The public properties and behavior are defined inside the
    @interface declaration.
    Once you’ve defined the interface for a class, including the
    properties and methods intended for public access, you need to
    write the code to implement the class behavior.
    @interface CalendarManager : NSObject

    View Slide

  19. RCTBridgeModule
    https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/
    WorkingwithProtocols/WorkingwithProtocols.html
    Objective-C allows you to define protocols, which declare the
    methods expected to be used for a particular situation.
    @protocol RCTBridgeModule
    + (NSString *)moduleName;
    @optional
    // snip
    @end
    A protocol to be implemented in native modules

    View Slide

  20. @“”, @[]?
    http://clang.llvm.org/docs/ObjectiveCLiterals.html
    Literals
    • @“” for NSString
    • @[] for NSArray / NSDictionary

    View Slide

  21. #import "RCTBridgeModule.h"
    @interface CalendarManager : NSObject
    @end
    @implementation CalendarManager
    RCT_EXPORT_MODULE()
    RCT_EXPORT_METHOD(addEvent:(NSString *)name at:(NSString *)location) {
    RCTLogInfo(@"Create an event: %@ at %@", name, location);
    }
    RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback) {
    NSArray *events = @[@"talk in 21cafe", @"write slides"];
    callback(@[[NSNull null], events]);
    }
    @end
    NATIVE MODULE EXAMPLE
    This is needed to be collected as
    a native module by the bridge

    View Slide

  22. RCT_EXPORT_MODULE
    RCT_EXPORT_MODULE()
    expanded to
    #define RCT_EXPORT_MODULE(js_name) \
    RCT_EXTERN void RCTRegisterModule(Class); \
    + (NSString *)moduleName { return @#js_name; } \
    + (void)load { RCTRegisterModule(self); }
    definitions
    by C-lang macro
    extern __attribute__((visibility("default"))) void RCTRegisterModule(Class);
    + (NSString *)moduleName { return @""; }
    + (void)load { RCTRegisterModule(self); }

    View Slide

  23. VISIBILITY?
    https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/
    SymbolVisibility.html
    Visibility attributes override the value specified with the
    -fvisibility flag at compile-time. Thus, adding the default
    visibility attribute causes a symbol to be exported in all cases,
    whereas adding the hidden visibility attribute hides it.
    extern __attribute__((visibility("default"))) void RCTRegisterModule(Class);
    + (NSString *)moduleName { return @""; }
    + (void)load { RCTRegisterModule(self); }
    Visibility “default” specifies exporting
    symbols to out of file scope

    View Slide

  24. +?
    A class method is a method that operates on class objects
    rather than instances of the class. In Objective-C, a class method
    is denoted by a plus (+) sign at the beginning of the method
    declaration and implementation
    extern __attribute__((visibility("default"))) void RCTRegisterModule(Class);
    + (NSString *)moduleName { return @""; }
    + (void)load { RCTRegisterModule(self); }
    Plus (+) sign to declare / implement
    class methods
    https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/
    ClassMethod.html

    View Slide

  25. @#js_name?
    https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
    When a macro parameter is used with a leading ‘#’, the
    preprocessor replaces it with the literal text of the actual
    argument, converted to a string constant. Unlike normal
    parameter replacement, the argument is not macro-expanded
    first. This is called stringification.
    #define RCT_EXPORT_MODULE(js_name) \
    RCT_EXTERN void RCTRegisterModule(Class); \
    + (NSString *)moduleName { return @#js_name; } \
    A combination of
    • string “@“
    • stringification feature in C-lang macro “#js_name”

    View Slide

  26. LOAD?
    Invoked whenever a class or category is added to the
    Objective-C runtime; implement this method to perform class-
    specific behavior upon loading.
    https://developer.apple.com/reference/objectivec/nsobject/1418815-load?language=objc
    extern __attribute__((visibility("default"))) void RCTRegisterModule(Class);
    + (NSString *)moduleName { return @""; }
    + (void)load { RCTRegisterModule(self); }
    A method to set up conditions for
    the class

    View Slide

  27. RCTRegisterModule?
    void RCTRegisterModule(Class moduleClass) {
    // initialization
    RCTAssert(
    [moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],
    @"%@ does not conform to the RCTBridgeModule protocol",
    moduleClass);
    // Register module
    [RCTModuleClasses addObject:moduleClass];
    }
    https://developer.apple.com/reference/objectivec/nsobject/1418893-conformstoprotocol
    Returns a Boolean value that indicates whether
    the receiver conforms to a given protocol.
    conformsToProtocol

    View Slide

  28. COLLECTING NATIVE MODULES
    https://developer.apple.com/reference/objectivec/nsobject/1418815-load?language=objc
    Run App Load Classes
    Register self as
    native module
    RCT_EXPORT_MODULE definitions
    extern __attribute__((visibility("default"))) void
    RCTRegisterModule(Class);
    + (NSString *)moduleName { return @""; }
    + (void)load { RCTRegisterModule(self); }

    View Slide

  29. INITIALIZING NATIVE MODULES
    NSMutableDictionary *moduleDataByName =
    [NSMutableDictionary new];
    for (Class moduleClass in RCTGetModuleClasses()) {
    NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
    // snip
    moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass
    bridge:self];
    moduleDataByName[moduleName] = moduleData;
    // snip
    } Native modules can call JavaScript
    through the bridge by this

    View Slide

  30. #import "RCTBridgeModule.h"
    @interface CalendarManager : NSObject
    @end
    @implementation CalendarManager
    RCT_EXPORT_MODULE()
    RCT_EXPORT_METHOD(addEvent:(NSString *)name at:(NSString *)location) {
    RCTLogInfo(@"Create an event: %@ at %@", name, location);
    }
    RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback) {
    NSArray *events = @[@"talk in 21cafe", @"write slides"];
    callback(@[[NSNull null], events]);
    }
    @end
    NATIVE MODULE EXAMPLE
    definitions for native functions

    View Slide

  31. RCT_EXPORT_METHOD
    + (NSArray *)__rct_export__142 {
    return @[@"", @"addEvent:(NSString *)name at:(NSString *)location"];
    }
    - (void)addEvent:(NSString *)name at:(NSString *)location {
    RCTLogInfo(@"Create an event: %@ at %@", name, location);
    }
    RCT_EXPORT_METHOD(addEvent:(NSString *)name at:(NSString *)location) {
    RCTLogInfo(@"Create an event: %@ at %@", name, location);
    }
    expanded to

    View Slide

  32. MACRO DEFINITIONS
    #define RCT_EXPORT_METHOD(method) \
    RCT_REMAP_METHOD(, method)
    #define RCT_REMAP_METHOD(js_name, method) \
    RCT_EXTERN_REMAP_METHOD(js_name, method) \
    - (void)method
    #define RCT_EXTERN_REMAP_METHOD(js_name, method) \
    + (NSArray *)RCT_CONCAT(__rct_export__, \
    RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
    return @[@#js_name, @#method]; \
    }

    View Slide

  33. -, __LINE__, __COUNTER__?
    https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
    https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
    This macro expands to the current input line
    number, in the form of a decimal integer
    constant.
    __LINE__
    This macro expands to sequential integral
    values starting from 0.
    __COUNTER__
    https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/
    DefiningClasses/DefiningClasses.html
    - The minus sign (-) at the front of the method
    name indicates that it is an instance method

    View Slide

  34. COLLECTING METHODS
    Method *methods = class_copyMethodList(object_getClass(cls), &methodCount);
    for (unsigned int i = 0; i < methodCount; i++) {
    Method method = methods[i];
    SEL selector = method_getName(method);
    if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) {
    IMP imp = method_getImplementation(method);
    NSArray *entries =
    ((NSArray *(*)(id, SEL))imp)(_moduleClass, selector);
    id moduleMethod =
    [[RCTModuleMethod alloc] initWithMethodSignature:entries[1]
    JSMethodName:entries[0]
    moduleClass:_moduleClass];
    [moduleMethods addObject:moduleMethod];
    }
    }

    View Slide

  35. OVERVIEW
    What is the bridge?
    What is native modules?
    Why the bridge is needed?
    advantages for users
    advantages for developers
    scripting native with React
    How does the bridge work?
    collecting native modules
    calling native functions
    calling JavaScript functions
    back

    View Slide

  36. PREFACE
    React Native apps have
    • some main threads
    • GCD queues for each modules
    setup by
    the bridge

    View Slide

  37. CALLING NATIVE FUNCTIONS
    import {
    NativeModules,
    } from 'react-native'
    const { CalendarManager } = NativeModules
    CalendarManager.addEvent(
    'talk at React Native Meetup #4',
    '21cafe'
    )

    View Slide

  38. NativeModules?
    • Facade for native modules
    • Calling functions through NativeModules enqueue JSON
    data for the calling
    MessageQueue.enqueueNativeCall
    NativeModules[aModule][aMethod]
    https://github.com/facebook/react-native/blob/master/Libraries/BatchedBridge/NativeModules.js

    View Slide

  39. ENQUEUE, THEN?
    The bridge processes enqueued callings after the end of JS
    execution
    https://tadeuzagallo.com/blog/react-native-bridge/

    View Slide

  40. TYPE CONVERSION FOR
    ARGUMENTS
    The bridge converts queued NSArray data by use of
    • type information from native module definitions
    • RCTConvert
    + (NSArray *)__rct_export__142 {
    return @[@"", @"addEvent:(NSString *)name at:(NSString *)location"];
    }
    - (void)addEvent:(NSString *)name at:(NSString *)location {
    RCTLogInfo(@"Create an event: %@ at %@", name, location);
    }
    type information
    https://github.com/facebook/react-native/blob/master/React/Base/RCTModuleMethod.m
    processed by
    the bridge

    View Slide

  41. RCTConvert?
    converter for JSON native value
    • JSON support
    • NSString
    • NSNumber
    • BOOL
    • NSArray
    • NSDictionary
    and more
    And you can define converter for your type like Enumerations
    https://github.com/facebook/react-native/search?q=RCTConvert

    View Slide

  42. EXAMPLE
    @[
    @[ @0 ], // module IDs
    @[ @1 ], // method IDs
    @[ // arguments
    @[
    @"talk at React Native Meetup",
    @"21cafe",
    ]
    ]
    ];
    CalendarManager.addEvent('talk at React Native Meetup #4', '21cafe')
    NSArray *moduleIDs = [RCTConvert
    NSNumberArray:requestsArray[RCTBridgeFieldRequestModuleIDs]];
    NSArray *methodIDs = [RCTConvert
    NSNumberArray:requestsArray[RCTBridgeFieldMethodIDs]];
    NSArray *paramsArrays = [RCTConvert
    NSArrayArray:requestsArray[RCTBridgeFieldParams]];
    // snip
    [self callNativeModule:[moduleIDs[index] integerValue]
    method:[methodIDs[index] integerValue]
    params:paramsArrays[index]];

    View Slide

  43. DISPATCH FROM NATIVE

    View Slide

  44. OVERVIEW
    What is the bridge?
    What is native modules?
    Why the bridge is needed?
    advantages for users
    advantages for developers
    scripting native with React
    How does the bridge work?
    collecting native modules
    calling native functions
    calling JavaScript
    functions back

    View Slide

  45. CALLING JAVASCRIPT
    FUNCTIONS BACK
    • by callback
    • by Promise
    • by sending event
    3 ways to call JavaScript functions back
    BatchedBridge
    enqueueCallback
    BatchedBridge
    enqueueJSCall
    https://github.com/facebook/react-native/blob/master/React/Base/RCTBatchedBridge.m
    arguments are
    converted to
    JSON

    View Slide

  46. BY CALLBACK
    RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback) {
    NSArray *events = @[@"talk in 21cafe", @"write slides"];
    callback(@[[NSNull null], events]);
    }
    error
    information arguments

    View Slide

  47. BY PROMISE
    RCT_EXPORT_METHOD(findEvents:(RCTPromiseResolveBlock)resolve
    rejecter:(RCTPromiseRejectBlock)reject) {
    NSArray *events = @[@"talk in 21cafe", @"write slides"];
    if (events) {
    resolve(events);
    }
    else {
    NSError *error = nil;
    reject(@"no events", @"no events", error);
    }
    }

    View Slide

  48. BY SENDING EVENT
    #import "RCTEventEmitter.h"
    @interface CalendarManager : RCTEventEmitter
    @end
    @implementation
    - (NSArray *)supportedEvents {
    return @[@"progress"];
    }
    @end

    View Slide

  49. BY SENDING EVENT
    RCT_EXPORT_METHOD(heavy) {
    dispatch_async(
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
    ^{
    int i = 0, j = 0;
    while (i < 10) {
    while (j < 10000) { ++j; }
    ++i;
    [self sendEventWithName:@"progress"
    body:[NSNumber numberWithInt:i]];
    }
    }
    );
    }

    View Slide

  50. SUMMARY
    • The approach “scripting native” is extremely powerful way for
    Web / native engineers.
    • “Learn once, write anywhere” for Web engineers
    • compile-less development for native engineers
    • Building native modules is simple enough.
    • Don’t be afraid, Let’s try.

    View Slide

  51. REFERENCES
    • https://code.facebook.com/posts/1014532261909640/react-
    native-bringing-modern-web-techniques-to-mobile/
    • http://facebook.github.io/react-native/docs/native-modules-
    ios.html
    • https://tadeuzagallo.com/blog/react-native-bridge/
    • http://qiita.com/janus_wel/items/93de843cc2243370fce4
    • https://github.com/facebook/react-native

    View Slide

  52. THANK YOU !!

    View Slide