从React-Native代码调用Android活动

26

我正在使用REACT-NATIVE构建Android应用程序。 我想从React-Native代码调用Android活动(例如,当我在React Native代码中点击按钮时,它应该调用Android活动)。

我有4个类文件

  • MainActivity.java(在Android Studio中打开时由react-native创建)
  • MainApplication.java(由react-native创建)
  • Login.java(Android活动文件)
  • Example.java(Android活动文件)

想要实现以下流程:

Login.java-> React-Native js-> Example.java

我已经阅读了以下链接,但无法理解:

https://dev59.com/WVwY5IYBdhLWcg3wWmxn#32825290

这里提出了类似的问题

React Native Android: Showing an Activity from Java

1个回答

50

要启动一个Android活动,您需要创建一个自定义的本地模块。假设有一个名为ActivityStarter的模块;它可以从JavaScript中使用,如下所示:

import { ..., NativeModules, ... } from 'react-native';

export default class DemoComponent extends Component {
    render() {
        return (
        <View>
            <Button
                onPress={() => NativeModules.ActivityStarter.navigateToExample()}
                title='Start example activity'
            />
        </View>
        );
    }
}

ActivityStarter 是一个 Java 类,它实现了一个名为 NativeModule 的 React Native Java 接口。这个接口的重要工作已经由 BaseJavaModule 完成,因此通常会扩展其中一个,即 BaseJavaModule 或者 ReactContextBaseJavaModule

class ActivityStarterModule extends ReactContextBaseJavaModule {

    ActivityStarterModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "ActivityStarter";
    }

    @ReactMethod
    void navigateToExample() {
        ReactApplicationContext context = getReactApplicationContext();
        Intent intent = new Intent(context, ExampleActivity.class);
        context.startActivity(intent);
    }
}

这个类的名字并不重要;JavaScript 中暴露出来的 ActivityStarter 模块名是从 getName() 方法中获取的。

react-native init 生成的默认应用包含一个 MainApplication 类,用于初始化 React Native。它继承了 ReactNativeHost,在其中重写了 getPackages 方法:

@Override
protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
            new MainReactPackage()
    );
}

如果你正在将React Native添加到现有应用程序中,此页面要求您将ActivityonCreate重写为以下内容:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mReactRootView = new ReactRootView(this);
    mReactInstanceManager = ReactInstanceManager.builder()
            .setApplication(getApplication())
            .setBundleAssetName("index.android.bundle")
            .setJSMainModuleName("index.android")
            .addPackage(new MainReactPackage())
            .setUseDeveloperSupport(BuildConfig.DEBUG)
            .setInitialLifecycleState(LifecycleState.RESUMED)
            .build();
    mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);

    setContentView(mReactRootView);
}

请注意addPackage(new MainReactPackage())。无论您使用哪种方法,都需要添加一个自定义包来公开我们的自定义模块。可能看起来像这样:

请注意addPackage(new MainReactPackage())。无论您使用哪种方法,都需要添加一个自定义包来公开我们的自定义模块。可能看起来像这样:

class ActivityStarterReactPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new ActivityStarterModule(reactContext));
        return modules;
    }

    // UPDATE: This method was deprecated in 0.47
    // @Override
    // public List<Class<? extends JavaScriptModule>> createJSModules() {
    //     return Collections.emptyList();
    // }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

最后,更新 MainApplication 来包含我们的新包:

@Override
protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
            new ActivityStarterReactPackage(), // This is it!
            new MainReactPackage()
    );
}

或者你可以使用addPackage(new ActivityStartecReactPackage())来添加到ReactInstanceManager.builder()中。

您可以在此处找到完整的自包含示例。


更新

从版本0.47开始,createJSModules已从ReactPackage接口中删除,并已注释掉样本。 如果由于某种原因而困在旧版本的RN上,则仍然需要它。


更新2019年3月

示例项目现在支持类似的iOS功能。


嗨@peter,你能告诉我这是否可行吗?一个Android应用程序与RN集成,其中页面A在Android中,页面B在RN中。在页面A上点击按钮后,RN活动启动并加载页面B。所以我的问题是,页面A上的按钮是否可以是RN组件而不是本地Android组件? - Aravind S
@Peter,能否私下联系您? - Paul
如果是通过按钮界面,那我可以使用它。我的需求有点不同,我想直接启动活动而不需要任何交互。这可行吗? - Jimit Patel
我认为这不应该是一个问题。NativeModules.ActivityStarter.navigateToExample() 不必作为单击按钮的结果被调用。 - Petter Hesselberg
你好,我正在尝试做类似的事情。我想通过一些参数启动我的应用程序,以便在无头任务前台服务中进行路由。我在我的模块中尝试了你的代码,并使用主要操作。但是出现了错误。找不到意图的活动。你能帮我吗?谢谢。 - shahrooz.bazrafshan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接