Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

最後のネイティブ・モジュール

 最後のネイティブ・モジュール

My talk for React Native Japan #15, showing how we've been putting up with native module boilerplate in React Native for far too long.

Jamie Birch

March 19, 2024
Tweet

More Decks by Jamie Birch

Other Decks in Technology

Transcript

  1. ݱࡏɺωΠςΟϒɾϞδϡʔϧ͸࡞ΓͮΒ͍ TurboModulesGuide ├── MyApp └── RTNCalculator ├── android │ ├──

    build.gradle │ └── src │ └── main │ └── java │ └── com │ └── rtncalculator │ ├── CalculatorPackage.java │ └── CalculatorModule.java │ │ ├── generated ├── ios │ ├── RTNCalculator.h │ └── RTNCalculator.mm ├── js │ └── NativeCalculator.ts ├── package.json └── rtn-calculator.podspec #import "RTNCalculatorSpec.h" #import "RTNCalculator.h" @implementation RTNCalculator RCT_EXPORT_MODULE() - (void)add:(double)a b:(double)b resolve:(RCTPromiseResolveBlock)resolve reject: (RCTPromiseRejectBlock)reject { NSNumber *result = [[NSNumber alloc] initWithInteger:a+b]; resolve(result); } - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared<facebook::react::NativeCalculatorSpecJSI>(params); } @end package com.rtncalculator import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.rtncalculator.NativeCalculatorSpec class CalculatorModule(reactContext: ReactApplicationContext) : NativeCalculatorSpec(reactContext) { override fun getName() = NAME override fun add(a: Double, b: Double, promise: Promise) { promise.resolve(a + b) } companion object { const val NAME = "RTNCalculator" } }
  2. UIApplication.sharedApplication.openURLOptionsCompletionHandler( NSURL.URLWithString("tel://0120-838-204"), {}, (success) => console.log(success), ); [ [UIApplication sharedApplication]

    openURL:[NSURL URLWithString:@"tel://0120-838-204"] options:@{} completionHandler:^(BOOL success) { NSLog(@"%d", success); } ]; Objective-C JavaScript ϓϩδΣΫγϣϯͷྗ
  3. ΋ͬͱ࢖͍΍͍͢ʂ . └── telephone.js import { Platform } from 'react-native';

    export function dial(phoneNumber) { switch(Platform.OS){ case "ios": UIApplication.sharedApplication.openURLOptionsCompletionHandler( NSURL.URLWithString(`tel://${phoneNumber}`), {}, (success) => console.log(success), ); break; case "android": Application.android.foregroundActivity.startActivity( new android.content.Intent( android.content.Intent.ACTION_DIAL, android.net.Uri.parse(`tel:${phoneNumber}`), ) ); break; } }
  4. σϞ ᶃ ॆిΛ֬ೝ͢Δ import { useEffect, useState } from "react";

    import { StyleSheet, Text, View } from "react-native"; export default function App() { const [batteryLevel, setBatteryLevel] = useState(-1); useEffect(() => { setBatteryLevel(UIDevice.currentDevice.batteryLevel); }, []); return ( <View style={styles.container}> <Text>ॆిɿ {batteryLevel * 100}%</Text> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: "center", justifyContent: "center", }, });
  5. σϞ ᶄ ωΠςΟϒɾσʔλɾϩΪϯά import { useEffect } from "react"; import

    { View } from "react-native"; export default function App() { useEffect(() => { const rootView = UIApplication.sharedApplication.keyWindow.rootViewController.view; console.log(rootView.debugDescription); }, []); return <View />; } LOG <RCTRootView: 0x10550eef0; frame = (0 0; 393 852); autoresize = W+H; backgroundColor = <UIDynamicSystemColor: 0x600001730300; name = systemBackgroundColor>; layer = <CALayer: 0x60000022f0c0>>
  6. σϞ ᶅ ϏϡʔͷόοΫάϥ΢ϯυɾΧϥʔΛมߋ͢Δ import { Button, View, StyleSheet } from

    "react-native"; export default function App() { return ( <View style={styles.container}> <Button title="ృΔ" onPress={() => { const rootView = UIApplication.sharedApplication.keyWindow.rootViewController.view; rootView.backgroundColor = UIColor.systemMintColor; }} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: "center", justifyContent: "center", }, });