Android平台扩展@ohos接口
说明:
Android平台上扩展@ohos接口,以testplugin.hello接口为例(假定@ohos.testplugin是OpenHarmony跨平台API)。
导入模块
// xxx.ets
import testplugin from '@ohos.testplugin';
接口
| 名称 | 参数 | 返回类型 | 描述 |
|---|---|---|---|
| hello | void | void | 在Android侧打印日志"hello from java" |
// xxx.ets
testplugin.hello();
步骤
为了调用Android Java API,本质是要实现JS调用Java的能力。跨平台推荐JS -> C/C++ -> Java的调用路径,实现JS调用Android Java API。即在Android侧实现Java接口,再通过JNI机制注册Java模块;通过NAPI机制实现C/C++模块注册,供应用侧JS调用。
一、Android侧实现hello方法
// plugins/test_plugin/android/java/src/TestPlugin.java
package ohos.ace.plugin.testplugin;
import android.content.Context;
import android.util.Log;
public class TestPlugin {
private static final String LOG_TAG = "TestPlugin";
// 插件构造函数,供插件注册模块调用
public TestPlugin(Context context) {
// 调用注册插件的初始化方法
nativeInit();
}
// 实现hello模块
public void hello() {
Log.i(LOG_TAG, "TestPlugin: hello from java");
}
// 注册插件的初始化方法,供插件构造函数调用
protected native void nativeInit();
}
二、通过JNI调用Java hello方法
1、JNI(Java Native Interface)允许Java代码和C/C++代码交互,通过在C/C++侧注册Java模块,实现C/C++调用Java。
// plugins/test_plugin/android/java/jni/test_plugin_jni.cpp
static const JNINativeMethod METHODS[] = {
{ "nativeInit", "()V", reinterpret_cast<void*>(TestPluginJni::NativeInit) },
};
struct {
jmethodID hello;
jobject globalRef;
} g_pluginClass;
bool TestPluginJni::Register(void* env) {
auto* jniEnv = static_cast<JNIEnv*>(env);
jclass cls = jniEnv->FindClass("ohos/ace/plugin/testplugin/TestPlugin");
// 注册nativeInit函数
return jniEnv->RegisterNatives(cls, METHODS, sizeof(METHODS) / sizeof(METHODS[0]));
}
// Called by Java
void TestPluginJni::NativeInit(JNIEnv* env, jobject jobj) {
jclass cls = env->GetObjectClass(jobj);
// 获取hello方法的Method ID
g_pluginClass.hello = env->GetMethodID(cls, "hello", "()V");
}
// Called by C++
void TestPluginJni::Hello()
{
auto env = OH_Plugin_GetJniEnv();
// 通过JNI调用Java hello方法
env->CallVoidMethod(g_pluginClass.globalRef, g_pluginClass.hello);
}
2、对JNI方法进行封装。
// plugins/test_plugin/android/java/jni/test_plugin_impl.cpp
// 定义了插件注册常用的接口
#include "plugin_utils.h"
// RunTaskOnPlatform是框架提供的接口,将JNI方法抛到Platform线程异步执行
void TestPluginImpl::Hello()
{
PluginUtilsInner::RunTaskOnPlatform([]() { TestPluginJni::Hello(); });
}
三、通过插件机制注册Java方法,通过NAPI机制暴露JS hello方法
1、实现testplugin.hello对应的C/C++模块。
// plugins/test_plugin/js_test_plugin.cpp
static napi_value JSTestPluginHello(napi_env env, napi_callback_info info)
{
// 创建TestPlugin实例
auto plugin = TestPlugin::Create();
// 调用C++接口,Hello函数最终会调用TestPluginJni::Hello
plugin->Hello();
return nullptr;
}
// plugins/test_plugin/test_plugin.h
class TestPlugin {
public:
TestPlugin() = default;
virtual ~TestPlugin() = default;
static std::unique_ptr<TestPlugin> Create();
virtual void Hello() = 0;
};
// plugins/test_plugin/android/java/jni/test_plugin_impl.cpp
std::unique_ptr<TestPlugin> TestPlugin::Create()
{
return std::make_unique<TestPluginImpl>();
}
2、实现模块导出入口函数
// plugins/test_plugin/js_test_plugin.cpp
static napi_value TestPluginExport(napi_env env, napi_value exports)
{
static napi_property_descriptor desc[] = {
DECLARE_NAPI_FUNCTION("hello", JSTestPluginHello),
};
NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
return exports;
}
3、实现插件JNI注册函数
// plugins/test_plugin/js_test_plugin.cpp
// ANDROID_PLATFORM是针对Android平台特有的宏
#ifdef ANDROID_PLATFORM
static void TestPluginJniRegister()
{
// OH_Plugin_RegisterPlugin是框架提供的接口,实现插件JNI环境的注册
OH_Plugin_RegisterJavaPlugin(&TestPluginJni::Register, "ohos.ace.plugin.testplugin.TestPlugin");
}
#endif
4、注册模块
// plugins/test_plugin/js_test_plugin.cpp
static napi_module testPluginModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = TestPluginExport,
.nm_modname = "testPlugin",
.nm_priv = ((void*)0),
.reserved = { 0 },
};
extern "C" __attribute__((constructor)) void TestPluginRegister()
{
// 注册testPlugin模块,供JS调用
napi_module_register(&testPluginModule);
#ifdef ANDROID_PLATFORM
// JNI插件注册函数需要在Platform线程运行
OH_Plugin_RunAsyncTask(&TestPluginJniRegister, OH_PLUGIN_PLATFORM_THREAD);
#endif
}
附:GN配置
1、增加模块
// plugins/plugin_lib.gni
common_plugin_libs = [
"test_plugin",
]
2、编译js_test_plugin模块
// plugins/test_plugin/BUILD.gn
ohos_source_set(target_name) {
defines += invoker.defines
cflags_cc += invoker.cflags_cc
sources = [ "js_test_plugin.cpp" ]
deps = [
"//plugins/interfaces/native:ace_plugin_util_${platform}",
"//plugins/libs/napi:napi_${target_os}",
]
if (platform == "android") {
deps += [ "android/java:test_plugin_android_jni" ]
}
subsystem_name = "plugins"
part_name = "test_plugin"
}
3、编译Android平台特有代码
// plugins/test_plugin/android/java/BUILD.gn
import("//build/ohos.gni")
java_library("test_plugin_android_java") {
java_files = [ "src/TestPlugin.java" ]
subsystem_name = "plugins"
part_name = "test_plugin"
}
// 编译jar包
ohos_combine_jars("test_plugin_java") {
deps = [ ":test_plugin_android_java" ]
subsystem_name = "plugins"
part_name = "test_plugin"
jar_path = "${root_out_dir}/plugins/test_plugin/ace_test_plugin_android.jar"
}
ohos_source_set("test_plugin_android_jni") {
sources = [
"jni/test_plugin_impl.cpp",
"jni/test_plugin_jni.cpp",
]
defines = [ "ANDROID_PLATFORM" ]
deps = [
":test_plugin_java",
"//plugins/interfaces/native:ace_plugin_util_android",
]
subsystem_name = "plugins"
part_name = "test_plugin"
}