在 Android 上启用 TurboModule

1.启用NDK和原生

code-gen 将输出一些我们现在需要构建的 Java 和一些 C++ 代码。

让我们编辑您的模块级别 build.gradle以在块内包含下面详述的两个 块:externalNativeBuildandroid{}

android {
    defaultConfig {
        applicationId "com.awesomeproject"
        // ...

        // Add this block
        externalNativeBuild {
            ndkBuild {
                arguments "APP_PLATFORM=android-21",
                        "APP_STL=c++_shared",
                        "NDK_TOOLCHAIN_VERSION=clang",
                        "GENERATED_SRC_DIR=$buildDir/generated/source",
                        "PROJECT_BUILD_DIR=$buildDir",
                        "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
                        "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
                cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
                cppFlags "-std=c++17"
                targets "myapplication_appmodules"
            }
        }
    }

    // Add this block
    externalNativeBuild {
        ndkBuild {
            path "$projectDir/src/main/jni/Android.mk"
        }
    }
}

在同一个build.gradle文件中,在同一个文件中,android{}我们还添加以下部分:

android {
    // ...

    def reactAndroidProjectDir = project(':ReactAndroid').projectDir
    def packageReactNdkLibs = tasks.register("packageReactNdkLibs", Copy) {
        dependsOn(":ReactAndroid:packageReactNdkLibsForBuck")
        dependsOn("generateCodegenArtifactsFromSchema")
        from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
        into("$buildDir/react-ndk/exported")
    }

    afterEvaluate {
        preBuild.dependsOn(packageReactNdkLibs)
        configureNdkBuildDebug.dependsOn(preBuild)
        configureNdkBuildRelease.dependsOn(preBuild)
    }

    packagingOptions {
        pickFirst '**/libhermes.so'
        pickFirst '**/libjsc.so'
    }
}

最后,我们需要在src/main/jni名为的文件夹中创建一个 Makefile Android.mk,其内容如下:

THIS_DIR := $(call my-dir)

include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk

include $(CLEAR_VARS)

LOCAL_PATH := $(THIS_DIR)
LOCAL_MODULE := myapplication_appmodules

LOCAL_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) $(GENERATED_SRC_DIR)/codegen/jni

# Please note as one of the library listed is libreact_codegen_samplelibrary
# This name will be generated as libreact_codegen_
# where  is the one you specified in the Gradle configuration


LOCAL_SHARED_LIBRARIES := libjsi \
    libfbjni \
    libglog \
    libfolly_json \
    libyoga \
    libreact_nativemodule_core \
    libturbomodulejsijni \
    librrc_view \
    libreact_render_core \
    libreact_render_graphics \
    libfabricjni \
    libfolly_futures \
    libreact_debug \
    libreact_render_componentregistry \
    libreact_render_debug \
    libruntimeexecutor \
    libreact_codegen_rncore \
    libreact_codegen_samplelibrary

LOCAL_CFLAGS := \
    -DLOG_TAG=\"ReactNative\"
LOCAL_CFLAGS += -fexceptions -frtti -std=c++17 -Wall

include $(BUILD_SHARED_LIBRARY)

此设置将在您的项目上运行本机构建,并将编译由 codegen 生成的 C++ 文件。您将看到使用 Gradle 任务运行的本机构建:app:externalNativeBuildDebug

您现在可以通过运行您的 android 应用程序来验证一切是否正常:

yarn react-native run-android

2. Java - 提供ReactPackageTurboModuleManagerDelegate

现在是实际使用TurboModule 的时候了。首先,我们需要创建一个ReactPackageTurboModuleManager Delegate 子类,如下所示:

package com.awesomeproject;

import com.facebook.jni.HybridData;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.soloader.SoLoader;

import java.util.List;

public class MyApplicationTurboModuleManagerDelegate extends ReactPackageTurboModuleManagerDelegate {

    private static volatile boolean sIsSoLibraryLoaded;

    protected MyApplicationTurboModuleManagerDelegate(ReactApplicationContext reactApplicationContext, List packages) {
        super(reactApplicationContext, packages);
    }

    protected native HybridData initHybrid();

    public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
        protected MyApplicationTurboModuleManagerDelegate build(
                ReactApplicationContext context, List packages) {
            return new MyApplicationTurboModuleManagerDelegate(context, packages);
        }
    }

    @Override
    protected synchronized void maybeLoadOtherSoLibraries() {
        // Prevents issues with initializer interruptions.
        if (!sIsSoLibraryLoaded) {
            SoLoader.loadLibrary("myapplication_appmodules");
            sIsSoLibraryLoaded = true;
        }
    }
}

请注意SoLoader.loadLibrary参数(在这种情况下"myapplication_appmodules")应该与您之前创建LOCAL_MODULE :=的Android.mk文件中指定的参数相同。

然后,此类将负责加载 TurboModules,并负责在运行时使用 NDK 加载本机库构建。

3.适应你ReactNativeHost使用ReactPackageTurboModuleManager Delegate

然后,您可以将您创建的类提供给您的ReactNativeHost. 您可以ReactNativeHost通过搜索找到您的getReactNativeHost(). ReactNativeHost通常位于您的班级Application内。

找到它后,您需要添加getReactPackageTurboModuleManagerDelegateBuilder以下代码段中的方法:

public class MyApplication extends Application implements ReactApplication {

    private final ReactNativeHost mReactNativeHost =
        new ReactNativeHost(this) {
            @Override
            public boolean getUseDeveloperSupport() { /* ... */ }

            @Override
            protected List getPackages() { /* ... */ }

            @Override
            protected String getJSMainModuleName() {/* ... */ }

            @NonNull
            @Override
            protected ReactPackageTurboModuleManagerDelegate.Builder getReactPackageTurboModuleManagerDelegateBuilder() {
                return new MyApplicationTurboModuleManagerDelegate.Builder();
            }
        };
}

4. 扩展getPackages()您ReactNativeHost使用的

仍然在ReactNativeHost,我们需要扩展该getPackages()方法以包含新创建的 TurboModule。更新方法以包括以下内容:

public class MyApplication extends Application implements ReactApplication {

    private final ReactNativeHost mReactNativeHost =
        new ReactNativeHost(this) {
            @Override
            public boolean getUseDeveloperSupport() { /* ... */ }

            @Override
            protected List getPackages() {
                List packages = new PackageList(this).getPackages();

                // Add those lines
                packages.add(new TurboReactPackage() {
                    @Nullable
                    @Override
                    public NativeModule getModule(String name, ReactApplicationContext reactContext) {
                        if (name.equals(NativeAwesomeManager.NAME)) {
                            return new NativeAwesomeManager(reactContext);
                        } else {
                            return null;
                        }
                    }

                    @Override
                    public ReactModuleInfoProvider getReactModuleInfoProvider() {
                        return () -> {
                            final Map moduleInfos = new HashMap<>();
                            moduleInfos.put(
                                    NativeAwesomeManager.NAME,
                                    new ReactModuleInfo(
                                            NativeAwesomeManager.NAME,
                                            "NativeAwesomeManager",
                                            false, // canOverrideExistingModule
                                            false, // needsEagerInit
                                            true, // hasConstants
                                            false, // isCxxModule
                                            true // isTurboModule
                                    )
                            );
                            return moduleInfos;
                        };
                    }
                });
                return packages;
            }

            @Override
            protected String getJSMainModuleName() {/* ... */ }

            @NonNull
            @Override
            protected ReactPackageTurboModuleManagerDelegate.Builder getReactPackageTurboModuleManagerDelegateBuilder() {
                return new MyApplicationTurboModuleManagerDelegate.Builder();
            }
        };

5.C++为你类中的方法提供本地实现TurboModuleDelegate

如果您仔细查看MyApplicationTurboModuleManagerDelegate您之前创建的类,您会注意到其中一些方法是怎样的native。

因此,您需要提供一些 C++ 类来实现这些方法。具体来说,您将需要将这些文件添加到src/main/jni文件夹中:

  • MyApplicationTurboModuleManagerDelegate.hTurboModule Delegate 的头文件。
  • MyApplicationTurboModuleManagerDelegate.cpp上述头文件的实现。
  • MyApplicationModuleProvider.hTurboModule 提供程序的头文件,您可以在其中指定要加载的 TurboModule。
  • MyApplicationModuleProvider.cpp上述头文件的实现。
  • OnLoad.cpp将放置初始化代码的位置。特别是 TurboModule 使用 FBJNI,因此此类库的初始化就在那里。

这些文件的内容应如下所示:

请注意,kJavaDescriptor应该根据您为项目选择的包名称进行调整。

#include 
#include 

#include 
#include 

namespace facebook {
namespace react {

class MyApplicationTurboModuleManagerDelegate : public jni::HybridClass {
public:
  // Adapt it to the package you used for your Java class.
  static constexpr auto kJavaDescriptor =
      "Lcom/awesomeproject/MyApplicationTurboModuleManagerDelegate;";

  static jni::local_ref initHybrid(jni::alias_ref);

  static void registerNatives();

  std::shared_ptr getTurboModule(const std::string name, const std::shared_ptr jsInvoker) override;
  std::shared_ptr getTurboModule(const std::string name, const JavaTurboModule::InitParams ¶ms) override;

private:
  friend HybridBase;
  using HybridBase::HybridBase;

};

} // namespace react
} // namespace facebook


#include "MyApplicationTurboModuleManagerDelegate.h"
#include "MyApplicationModuleProvider.h"

namespace facebook {
namespace react {

jni::local_ref MyApplicationTurboModuleManagerDelegate::initHybrid(jni::alias_ref) {
  return makeCxxInstance();
}

void MyApplicationTurboModuleManagerDelegate::registerNatives() {
  registerHybrid({
    makeNativeMethod("initHybrid", MyApplicationTurboModuleManagerDelegate::initHybrid),
  });
}

std::shared_ptr MyApplicationTurboModuleManagerDelegate::getTurboModule(const std::string name, const std::shared_ptr jsInvoker) {
  // Not implemented yet: provide pure-C++ NativeModules here.
  return nullptr;
}

std::shared_ptr MyApplicationTurboModuleManagerDelegate::getTurboModule(const std::string name, const JavaTurboModule::InitParams ¶ms) {
  return MyApplicationModuleProvider(name, params);
}

} // namespace react
} // namespace facebook


#pragma once

#include 
#include 

#include 

namespace facebook {
namespace react {

std::shared_ptr MyApplicationModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams ¶ms);

} // namespace react
} // namespace facebook

请调整samplelibrary.h导入以匹配您在构建应用程序时提供的相同库名称。这是由 codegen 创建的 C++ 生成文件。

如果您有多个 TurboModule,您还可以在此处指定多个提供程序。samplelibrary特别是在这个例子中,我们从(我们指定的那个)中寻找一个 TurboModule,然后我们回退到rncoreModule Provider(包含所有核心模块)。

#include "MyApplicationModuleProvider.h"

#include 
#include 

namespace facebook {
namespace react {

std::shared_ptr MyApplicationModuleProvider(const std::string moduleName, const JavaTurboModule::InitParams ¶ms) {
    auto module = samplelibrary_ModuleProvider(moduleName, params);
    if (module != nullptr) {
      return module;
    }

    return rncore_ModuleProvider(moduleName, params);
}

} // namespace react
} // namespace facebook


#include 
#include "MyApplicationTurboModuleManagerDelegate.h"

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
  return facebook::jni::initialize(vm, [] {
    facebook::react::MyApplicationTurboModuleManagerDelegate::registerNatives();
  });
}

6. 在您的应用程序中启用该useTurboModulesonCreate

现在您终于可以TurboModule 在您的应用程序中启用支持了。为此,您需要在Application方法中打开

useTurboModule标志。onCreate

public class MyApplication extends Application implements ReactApplication {

    @Override
    public void onCreate() {
        ReactFeatureFlags.useTurboModules = true;
        //...
    }

现在是时候再次运行您的 Android 应用以验证一切是否正常:

yarn react-native run-android

你可能感兴趣的:(Android,C++,Java,android,react,native,react.js)