本文中React Native简称“RN”
安装RN可参考文档RN环境安装参考
npx react-native init XXX
初始化RN项目。RNEffectModule是RN与原生Android交互的类,负责处理按钮点击与A交互;
reacNativeWithActionName是按钮点击的方法,通过传递的参数(Record、Draft、Duet)来确定点击的是哪个按钮
/** * Sample React Native App * https://github.com/facebook/react-native * * @format */ import React from 'react'; import type {PropsWithChildren} from 'react'; import { SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, useColorScheme, View, Button, NativeModules,//RN与原生交互模型 } from 'react-native'; import { Colors, DebugInstructions, Header, LearnMoreLinks, ReloadInstructions, } from 'react-native/Libraries/NewAppScreen'; import { RNLocalize, } from 'react-native-localize'; type SectionProps = PropsWithChildren<{ title: string; }>; <StatusBar barStyle="light-content" backgroundColor="#7b1fa2" /> function Section({children, title}: SectionProps): React.JSX.Element { const isDarkMode = useColorScheme() === 'dark'; return ( <View style={styles.sectionContainer}> </View> ); } function App(): React.JSX.Element { const isDarkMode = useColorScheme() === 'dark'; const backgroundStyle = { backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, }; //构造原生交互模型 const RNEffectModule = NativeModules.RNEffectModule; return ( <SafeAreaView style={backgroundStyle}> <StatusBar // barStyle={isDarkMode ? 'light-content' : 'dark-content'} barStyle={'light-content'} backgroundColor={backgroundStyle.backgroundColor} /> <ScrollView contentInsetAdjustmentBehavior="automatic" style={backgroundStyle}> <Header /> <View style={{ backgroundColor: isDarkMode ? Colors.black : Colors.white, }}> </View> <View> <Button //拍摄按钮 title="Record" onPress={() => RNEffectModule.reacNativeWithActionName("Record")} color="#f54343" /> <Button //草稿箱按钮 title="Draft" onPress={() => RNEffectModule.reacNativeWithActionName("Draft")} backgroundColor="#999999" /> <Button //视频合拍按钮 title="Duet" onPress={() => RNEffectModule.reacNativeWithActionName("Duet")} backgroundColor="#666666" /> </View> </ScrollView> </SafeAreaView> ); } const styles = StyleSheet.create({ sectionContainer: { marginTop: 32, paddingHorizontal: 24, }, sectionTitle: { fontSize: 24, fontWeight: '600', }, sectionDescription: { marginTop: 8, fontSize: 18, fontWeight: '400', }, highlight: { fontWeight: '1700', }, }); export default App;
具体Android集成配置参考标准集成文档快速接入, 本文只说明与Android原生集成桥接的部分和需要注意的事项。
参考Demo中app Module下的RNEffectModule.kt(接收RN对应响应事件) 和 EOReactNativePackage.kt(注册原生模块)
桥接文件对应代码实现
RNEffectModule.kt
package com.volcengine.effectone import androidx.fragment.app.FragmentActivity import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.volcengine.effectone.business.EODuetInitHelper import com.volcengine.effectone.business.EOQuickInitHelper import com.volcengine.effectone.business.R import com.volcengine.effectone.utils.runOnUiThread import com.volcengine.effectone.widget.EOToaster class RNEffectModule(reactContext: ReactApplicationContext?) : ReactContextBaseJavaModule(reactContext) { companion object { private const val TAG = "RNEffectModule" } private val reactContext = reactContext override fun getName(): String { return "RNEffectModule" } @ReactMethod fun reacNativeWithActionName(actionName: String) { runOnUiThread { when (actionName) { "Record" -> { if (MainActivity.authResult) { reactContext?.currentActivity?.let { EOQuickInitHelper.startRecorder(it as FragmentActivity) } } else { reactContext?.currentActivity?.let { EOToaster.show(it, R.string.eo_frontpage_auth_fail) } } } "Draft" -> { if (MainActivity.authResult) { reactContext?.currentActivity?.let { EOQuickInitHelper.startDraft(it as FragmentActivity) } } else { reactContext?.currentActivity?.let { EOToaster.show(it, R.string.eo_frontpage_auth_fail) } } } "Duet" -> { if (MainActivity.authResult) { reactContext?.currentActivity?.let { EODuetInitHelper.startDuet(it as FragmentActivity) } } else { reactContext?.currentActivity?.let { EOToaster.show(it, R.string.eo_frontpage_auth_fail) } } } } } } }
EOReactNativePackage.kt
package com.volcengine.effectone import android.view.View import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ReactShadowNode import com.facebook.react.uimanager.ViewManager class EOReactNativePackage: ReactPackage { override fun createNativeModules(reactApplicationContext: ReactApplicationContext): MutableList<NativeModule> { return mutableListOf(RNEffectModule(reactApplicationContext)) } override fun createViewManagers(p0: ReactApplicationContext): MutableList<ViewManager<View, ReactShadowNode<*>>> { return mutableListOf() } }
使用EOQuickInitHelper.kt 接口启动对应界面时, 因为有请求权限的逻辑, 要保证在UI或主线程中使用.
使用EOQuickInitHelper.kt 接口启动对应界面时, 接口参数是FragmentActivity, 如果当前的是ReactActivity()可以强转一下。
@ReactMethod fun reacNativeWithActionName(actionName: String) { runOnUiThread { when (actionName) { "Record" -> { if (MainActivity.authResult) { reactContext?.currentActivity?.let { EOQuickInitHelper.startRecorder(it as FragmentActivity) } } else { reactContext?.currentActivity?.let { EOToaster.show(it, R.string.eo_frontpage_auth_fail) } } } ...... } } }
JDK版本和Kotlin版本要根据RN支持的版本进行动态修改, 修改Demo种version.gradle文件中的版本配置。
setting.gradle中修改EffectOne maven仓库的配置模式改为RepositoriesMode.PREFER_SETTINGS,优先仓库的配置。
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { google() mavenCentral() maven { url 'https://artifact.bytedance.com/repository/Volcengine/' } maven { url "https://artifact.bytedance.com/repository/thrall_ck/" credentials { username = MAVEN_USER_NAME password = MAVEN_PASS_WORD } authentication { digest(BasicAuthentication) } } } } ......
运行文档中Demo时要注意配置MAVEN_USER_NAME和MAVEN_PASS_WORD, 否则无法拉取EffectOne的SDK。
在模拟器运行时,终端RN项目根目录下,执行npx react-native run-android
或者yarn npx react-native run-android
(如果安装了yarn
)。