HarmonyOS鸿蒙Next中Native C++代码在模拟器中测试失败

HarmonyOS鸿蒙Next中Native C++代码在模拟器中测试失败

import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';

const DOMAIN = 0x0000;

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  @State message1: string = 'Hello World1';

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize($r('app.float.page_text_font_size'))
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            this.message = testNapi.add(8,3).toString();
            hilog.info(DOMAIN, 'testTag', 'Test NAPI 8 + 3 = %{public}d', testNapi.add(8, 3));
            // hilog.info(DOMAIN, 'testTag', 'Test NAPI 8 - 3 = %{public}d', testNapi.sub(8, 3));
          })
        Blank()
        Text(this.message1)
          .fontSize($r('app.float.page_text_font_size'))
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            this.message1 = testNapi.sub(8,3).toString();
            // hilog.info(DOMAIN, 'testTag', 'Test NAPI 8 + 3 = %{public}d', testNapi.add(8, 3));
            hilog.info(DOMAIN, 'testTag', 'Test NAPI 8 - 3 = %{public}d', testNapi.sub(8, 3));
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}
#include "napi/native_api.h"

static napi_value add(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);

    return sum;

}

static napi_value sub(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value diff;
    napi_create_double(env, value0 - value1, &diff);

    return diff;

}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"add", nullptr, add, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"sub", nullptr, sub, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}

真机测试,点击HelloWorld1能正常显示,在模拟器中测试,HelloWorld正常,HelloWorld1报错如下:

01-30 11:06:29.096 4692-28244 C03f00/ArkCompiler E [ArkRuntime Log] TypeError: undefined is not callable

01-30 11:06:29.096 4692-28244 C01304/Simulator E [Simulator Log]Error name:TypeError

01-30 11:06:29.096 4692-28244 C01304/Simulator E [Simulator Log]Error message:undefined is not callable

01-30 11:06:29.096 4692-28244 C01304/Simulator E [Simulator Log]Stacktrace:

01-30 11:06:29.096 4692-28244 C01304/Simulator E [Simulator Log] at anonymous entry (entry/src/main/ets/pages/Index.ets:28:38)

01-30 11:06:31.344 4692-28244 A00000/testTag I Test NAPI 8 + 3 = 11

是何原因?


更多关于HarmonyOS鸿蒙Next中Native C++代码在模拟器中测试失败的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复

开发者您好,我这边全量使用的您问题描述中的代码,API版本为API20,模拟器版本为6.0.0(20),型号为:Mate 70PRo。目前真机运行和模拟器运行点击HelloWorld、HelloWorld1都是正常运行的。您这边报错的话方便提供以下信息方便我们这边具体定位么?

  1. 项目版本号
  2. IDE版本号:Help-About DevEco Studio,查看IDE版本号
  3. 模拟器版本号: Tools-Device Manager

更多关于HarmonyOS鸿蒙Next中Native C++代码在模拟器中测试失败的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


开发者您好,参考预览器的使用约束:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-previewer-debug#section24576302190 。 目前预览器不支持C++调试。

说错了,是在预览器中,版本信息见下面截图。

cke_310.png

cke_547.png cke_838.png

版本号信息见截图。

鸿蒙Next的Native C++代码在模拟器中测试失败,通常与NDK版本、ABI兼容性或模拟器配置有关。请确认使用的DevEco Studio版本与NDK工具链匹配,并检查C++运行库(如libc++_shared.so)是否正确打包。同时,确保模拟器镜像支持对应的Native API级别。

从你提供的代码和日志来看,问题出在 testNapi.sub 函数在模拟器环境中未被正确导出或加载,导致其在运行时为 undefined,从而引发 undefined is not callable 错误。而 testNapi.add 函数在真机和模拟器上都能正常工作。

根本原因分析:

  1. 模块加载与注册时序问题(最可能):在 HarmonyOS Next 的模拟器环境中,Native API(NAPI)模块的加载、注册和 JavaScript 引擎初始化的时序可能与真机存在细微差异。你的代码使用 __attribute__((constructor)) 在动态库加载时自动调用 RegisterEntryModule 进行注册。在模拟器上,有可能在 sub 函数被调用时,其注册信息尚未完全同步到 JavaScript 引擎的上下文中,而 add 函数可能因为调用稍晚或缓存机制而可用。这是一种典型的“未定义”行为,高度依赖于运行时环境。

  2. 模拟器与真机环境差异:模拟器(通常基于 x86/64 架构)和真机(ARM 架构)在底层系统库、编译工具链或 Ark 引擎的具体实现上可能存在未被察觉的差异,导致动态库中函数符号的解析或绑定行为不一致。

解决方案:

首选方案:使用标准的 NAPI 模块注册宏 HarmonyOS NAPI 提供了更可靠的模块注册方式。请修改你的 entry.cpp 文件,替换现有的模块注册代码(从 EXTERN_C_START 到文件末尾)。

将这部分代码:

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"add", nullptr, add, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"sub", nullptr, sub, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}

替换为:

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"add", nullptr, add, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"sub", nullptr, sub, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

// 使用 HarmonyOS NAPI 提供的宏进行模块声明
NAPI_MODULE(entry, Init)

NAPI_MODULE 宏会处理模块注册的细节,确保在不同环境下的兼容性。

实施步骤:

  1. 使用上述代码修改你的 entry.cpp
  2. 执行完整的清理构建:在 DevEco Studio 中,点击菜单栏的 Build -> Clean Project,然后点击 Build -> Build HAP(s)。这步至关重要,以确保旧的二进制文件被清除。
  3. 重新运行到模拟器上进行测试。

其他检查点(如果问题依旧):

  • 确认 CMakeLists.txt 配置:确保你的 Native 模块在 CMakeLists.txt 中正确配置,并且 libentry.so 被成功打包到 HAP 中。
  • 检查 ArkTS 导入语句:你的导入语句 import testNapi from 'libentry.so'; 是正确的。确保没有拼写错误。
  • 查看完整日志:在 DevEco Studio 的 Log 面板中,过滤 SimulatorArkCompiler 标签,查看在应用启动时是否有关于 NAPI 模块加载失败或警告的早期日志。

总结,问题根源在于模拟器环境中自动构造函数注册模块的方式存在不确定性。采用 HarmonyOS NAPI 框架提供的标准 NAPI_MODULE 宏进行注册,是解决此类跨环境兼容性问题的最有效方法。

回到顶部