鸿蒙 IM 开发 - Protobuf 使用与编译

1,312 阅读9分钟

背景

最近在开发鸿蒙的IM项目,既然是IM项目必然存在网络通信,数据库存储等相关知识,这篇文章先不提及一些IM的核心内容,而是先说一下如何使用Protobuf库。

题外话

好久没有输出文章了,原因是24年10月份工作发生了变化,去了新公司做IM项目,临近过年终于有时间总结一下输出一下,在此也给大家拜个晚年了!祝大家在新的一年,身体健康,升职加薪!

针对IM通信层,为什么选择使用Protobuf作为数据包格式?
  1. 高效的序列化与反序列化
    Protobuf 在数据序列化时使用二进制格式,比 JSON、XML 等文本格式更加紧凑,占用更少的带宽,并且解析速度更快。
  2. 跨平台兼容性
    Protobuf 提供多种语言的官方支持,包括 Java、Kotlin、C++、Go、Python 等,使得客户端和服务器可以较为容易实现跨平台通信。
  3. 灵活的可扩展性
    Protobuf 允许定义消息时保持向后兼容和向前兼容,这使得新增字段不会影响已有的功能,适合快速迭代的 IM 应用开发。
  4. 易于定义和维护
    通过 .proto 文件定义数据结构,开发者可以清晰地管理和维护通信协议,减少接口变更的成本。
  5. 安全性更高
    由于 Protobuf 采用二进制编码,不易被人直接阅读,有助于在一定程度上提升通信数据的安全性。
  6. 自动生成代码
    Protobuf 支持通过编译自动生成不同编程语言的数据类,减少手写解析代码的工作量,提高开发效率。
在鸿蒙napi通信过程,使用protobuf字节数组进行数据传输

我们的场景是这样的,实现一套类似企业微信的能力,核心的一块就是数据库,但在比较中,我们AndroidiOS都采用了腾讯开源的WCDB数据库,它在基于Sqlite的基础上进行了修改与优化,因此在鸿蒙侧也希望可以使用,针对数据库后续会单独总结一篇文章记录。

由于在业务中,需要频繁对数据库操作,而且需要传递数据量较为大的表结构数据集,而WCDB在鸿蒙侧只能在native侧使用,这就需要考虑etsnative通信性能了,经过查阅资料,最终选择使用PB格式进行与native侧数据通信。

whiteboard_exported_image.png

通过上图,我们就需要存在两部分解析,一部分是在ets侧实现PB编解码,同样在native侧实现实现PB编解码。

ETS 侧使用 Protobuf

鸿蒙官方文档中并未给出Protobuf如何使用,毕竟这个协议是Google制定的,Protobuf数据编码规范而非完整的通信协议,因此所有的编程语言都可以支持。

花了一段时间检索,在鸿蒙三方库中有三个针对PB的编解码库,看到一个热度最高的protobufjs,它可以自动执行.proto解析脚本,并生成.ts文件 & .js文件

如何使用就不过多阐述了,三方库有详细的使用,注意一点就是:最好不要在.proto文件中写太多的注释,会导致生成的文件不对,而且编译器也不能在编译期发现,也没有任何报错。

示例
import { conversation } from 'pb_table/conversation'

private async saveToConversationTable(convs: Conversation[]): Promise<number> {
  try {
    console.error('PB GENERATE START:', "START");
    // 将 `convs` 数组映射为 Protobuf 格式的 Conversation 实例
    const convsPBArray = convs.map(conv =>
    // 创建PB对象的会话数据信息
    conversation.Conversation.create({
      url: conv.faceUrl,
      conversationId: conv.conversationId,
      name: conv.showName,
      isTop: false,
    })
    );
    // 创建 Protobuf 的 ConversationList
    let convsPB = conversation.ConversationList.create({
      conversations: convsPBArray
    });
    console.error('PB GENERATE START:', "END");
    // 执行插入操作并等待完成
    await ConversationOp.getInstance().insertConversations(convsPB);
    console.error('WCDB INSERT  START:', "END");
    return 0;
  } catch (error) {
    console.error('Error saving conversations:', error);
    return -1;
  }
}

执行插入会话表,这里会调用 encode() 方法转成字节数组,再调用napi将字节数组传递到native侧执行数据库操作。

insertConversations(convs: conversation.ConversationList): Promise<boolean> {
  return new Promise((resolve, reject) => {
    try {
      let arrayBuffer: Uint8Array = conversation.ConversationList.encode(convs).finish(); // 调用 finish() 方法获取字节数组
      const result = databaseNapi.insertConversations(arrayBuffer);
      if (result >= 0) {
        resolve(true);
      } else {
        reject(new Error('Failed to insert conversations into the database.'));
      }
    } catch (error) {
      console.error('Error in insertConversations:', error);
      reject(error);
    }
  });
}

综上在ETS侧使用Protobuf还是比较容易的,但是现在存在一个问题在native侧也同样需要使用Protobuf

HarmonyOS Native(C层编译 Protobuf库)

由于没有编译Protobuf的经验而又是鸿蒙系统,不知道是否存在兼容性问题。在Github上的Protobuf库中我们可以拿到clone地址。

github.com/protocolbuf…

我这里没有使用最新的release包编译,因为之前本机上的protobuf版本是29.1版本,由于鸿蒙Native侧暂时需要使用命令将.proto文件转成C++代码,因此需要确保编译库的版本与本机protobuf版本一致。

git clone https://github.com/protocolbuffers/protobuf.git
# 进入项目目录
cd protobuf
# 切换到 29.1 版本的 tag
git checkout v29.1
# 注意这里 项目依赖了子仓库需要执行下方命令去依赖
git submodule update --init --recursive

此时v29.1代码已经克隆下来了,并要确保有cmake环境。

cmake
    -DCMAKE_CXX_STANDARD=17 \
    -Dprotobuf_BUILD_TESTS=OFF \
    -DBUILD_SHARED_LIBS=OFF \
    -Dprotobuf_PROTOC_EXE=/opt/homebrew/bin/protoc \
    -DCMAKE_INSTALL_INCLUDEDIR=include \
    -DCMAKE_TOOLCHAIN_FILE=/Users/EdisonLi/Library/OpenHarmony/Sdk/13/native/build/cmake/ohos.toolchain.cmake \
    -DOHOS_ARCH=arm64-v8a \
    -DCMAKE_INSTALL_PREFIX=/Users/EdisonLi/Downloads/protobuf/install \
    -S /Users/EdisonLi/Downloads/protobuf \
    -B /Users/EdisonLi/Downloads/protobuf/build

之后就会生成build配置文件,如下。

image.png

然后执行如下命令进行编译。

cmake --build /Users/EdisonLi/Downloads/protobuf/build --target install

成功后则生成install & bin & include 文件夹,

image.png

.proto 文件转 C++ 代码

我们就可以使用bin中的 protc命令将 .proto 文件转 C++ 代码了。

export PATH=/Users/EdisonLi/Downloads/protobuf/install/bin:$PATH
protoc --version
protoc --cpp_out=out conversation.proto
鸿蒙项目中编译protobuf库

C++代码流程已完成,但将C文件在项目中编译是报错的,需要引入编译v29.1的头文件。 我们将编译好的 inclule 文件夹全部复制到项目中。

image.png

并将libs中的静态库一并复制,由于方便后续排查问题,以及不想单独编译成一个protobuf.so,所以当时我配置 cmake -DBUILD_SHARED_LIBS=OFF,如果需要打动态库则可设置为cmake -DBUILD_SHARED_LIBS=ON

之后我们需要单独在cmake配置中声明如下:

# cmake/thirdparty.cmake

# WCDB 配置
add_library(WCDB SHARED IMPORTED)
set_target_properties(WCDB
    PROPERTIES
    IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/third_party/wcdb/libs/${OHOS_ARCH}/libWCDB.so
)
# Protobuf 及 Abseil 静态库列表
set(PROTOBUF_LIBS
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libprotobuf-lite.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libprotobuf.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libprotoc.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_bad_any_cast_impl.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_bad_optional_access.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_bad_variant_access.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_base.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_city.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_civil_time.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_cord.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_cord_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_cordz_functions.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_cordz_handle.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_cordz_info.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_cordz_sample_token.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_crc32c.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_crc_cord_state.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_crc_cpu_detect.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_crc_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_debugging_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_demangle_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_die_if_null.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_examine_stack.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_exponential_biased.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_failure_signal_handler.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_commandlineflag.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_commandlineflag_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_config.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_marshalling.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_parse.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_private_handle_accessor.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_program_name.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_reflection.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_usage.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_flags_usage_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_graphcycles_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_hash.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_hashtablez_sampler.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_int128.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_kernel_timeout_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_leak_check.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_entry.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_flags.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_globals.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_initialize.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_check_op.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_conditions.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_fnmatch.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_format.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_globals.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_log_sink_set.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_message.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_nullguard.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_internal_proto.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_severity.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_log_sink.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_low_level_hash.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_malloc_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_periodic_sampler.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_distributions.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_internal_distribution_test_util.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_internal_platform.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_internal_pool_urbg.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_internal_randen.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_internal_randen_hwaes.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_internal_randen_hwaes_impl.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_internal_randen_slow.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_internal_seed_material.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_seed_gen_exception.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_random_seed_sequences.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_raw_hash_set.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_raw_logging_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_scoped_set_env.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_spinlock_wait.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_stacktrace.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_status.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_statusor.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_str_format_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_strerror.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_string_view.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_strings.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_strings_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_symbolize.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_synchronization.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_throw_delegate.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_time.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_time_zone.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libabsl_vlog_config_internal.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libupb.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libutf8_range.a
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/libs/${OHOS_ARCH}/libutf8_validity.a
)

这里需要把所有的.a文件都编译进来,由于protobuf使用了abseil,所以大部分都是这个库的引用。由于abseil提供非常稳定实用的基础库,所以后续也可用上。 此时编译就成功了。

举个解析的例子

image.png

上述代码是通过这个命令生成

protoc --cpp_out=out conversation.proto

napi_value insertConversations(napi_env env, napi_callback_info info) {
    std::vector<uint8_t> num_array = {};
    uint8ArrayPassingTs2Napi(env, info, num_array);
    conversation::ConversationList conversationListPb;
    // 先解析字节数组,转换成pb对象
    if (!conversationListPb.ParseFromArray(num_array.data(), num_array.size())) {
        napi_throw_error(env, nullptr, "Failed to parse protobuf data");
        return nullptr;
    }
    std::unique_ptr<ConversationOp> convOp = std::make_unique<ConversationOp>();
    const int count = conversationListPb.conversations_size();
    napi_value result;
    if (count > 0) {
        std::vector<Conversation> convContainer;
        for (int i = 0; i < count; i++) {
            const conversation::Conversation &pbConv = conversationListPb.conversations(i); // 转 C++ pb对象模型。
            Conversation wcdbConv;
            // string to int64
            wcdbConv.conversationId = std::stoll(pbConv.conversation_id());
            switch (pbConv.not_disturb_type()) {
                case conversation::Conversation_NotDisturbType_NONE:
                    wcdbConv.notDisturbType = "NONE";
                    break;
                case conversation::Conversation_NotDisturbType_MUTE:
                    wcdbConv.notDisturbType = "MUTE";
                    break;
                case conversation::Conversation_NotDisturbType_CUSTOM:
                    wcdbConv.notDisturbType = "CUSTOM";
                    break;
                default:
                    wcdbConv.notDisturbType = "UNKNOWN";
            }
            
            // 使用获取pb数据。
            wcdbConv.isGroup = pbConv.is_group();
            wcdbConv.url = pbConv.url();
            wcdbConv.name = pbConv.name();
            wcdbConv.lastMessage = pbConv.last_message();
            wcdbConv.lastServerMsgId = pbConv.last_server_msg_id();
            wcdbConv.lastTime = pbConv.last_time();
            wcdbConv.unreadCount = pbConv.unread_count();
            wcdbConv.readServMsgID = pbConv.read_serv_msg_id();
            wcdbConv.hide = pbConv.hide() ? 1 : 0;  // bool转int
            wcdbConv.sender = pbConv.sender();
            wcdbConv.hasAtYou = pbConv.has_at_you();
            wcdbConv.hasAtAll = pbConv.has_at_all();
            wcdbConv.isTop = pbConv.is_top();
            wcdbConv.topId = pbConv.top_id();
            wcdbConv.disturbId = pbConv.disturb_id();
            wcdbConv.isStar = pbConv.is_star();
            wcdbConv.starId = pbConv.star_id();
            wcdbConv.relation = pbConv.relation();
            wcdbConv.relationId = pbConv.relation_id();
            wcdbConv.lastNameTime = pbConv.last_name_time();
            const std::string& draftStr = pbConv.draft_info();
            wcdbConv.draftInfo.assign(draftStr.begin(), draftStr.end());
            convContainer.push_back(wcdbConv);
        }
        int32_t insertCounts = !convOp->insertConversations(convContainer);
        if (insertCounts >= 0) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "insertConv", "Failed to insert conversation: %d", insertCounts);
        }
        napi_create_int32(env, insertCounts, &result);
    } else {
        napi_create_int32(env, -1, &result);
    }
    
    return result;
}

此时native侧就能获取到ets侧传递过来的大数据了,然后再进行后续的数据库写入操作。

总结

至此鸿蒙的native能力的开发,实际上和Android都一样,后续会继续探讨WCDB数据库在鸿蒙中的应用。