服务端应用开发
=======

#### 场景介绍

[OH\_ContentEmbed](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-contentembed)内容嵌入模块提供对象编辑框架与技术，支持应用间文档嵌入与协同编辑。

OE服务端应用使用[OE Extension框架](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-extension-h)提供的接口，向客户端应用提供特定格式文档的嵌入与编辑能力。

#### 约束限制

在使用接口前，需先确认设备具备SystemCapability.ContentEmbed.ObjectEditor系统能力，判断方式请参阅[查询指定的系统能力是否被支持](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/init#caniuse)。并申请ohos.permission.REGISTER\_OBJECTEDITOR\_EXTENSION权限，配置方式请参阅[声明权限](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/declare-permissions)。

#### 接口说明

常用接口如下表所示。更多API说明请参考[OH\_ContentEmbed](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-contentembed)。

**表1** 服务端主要接口

| 接口名称 | 功能描述 |
| :-- | :-- |
| OH\_ContentEmbed\_Extension\_GetExtensionInstance | 从ExtensionAbility基类实例中获取对应的[OE Extension](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/content-embed-kit-terminology#oe-extension)实例。 |
| OH\_ContentEmbed\_Extension\_GetContentEmbedContext | 从OE Extension实例中获取其对应的OE Extension上下文对象。 |
| OH\_ContentEmbed\_Extension\_GetContext | 从OE Extension上下文中获取AbilityRuntime上下文。 |
| OH\_ContentEmbed\_Extension\_RegisterOnCreateFunc | 注册OE Extension实例创建时的生命周期函数。 |
| OH\_ContentEmbed\_Extension\_RegisterOnDestroyFunc | 注册OE Extension实例销毁时的生命周期函数。 |
| OH\_ContentEmbed\_Extension\_RegisterOnObjectAttachFunc | 注册[客户端OE对象](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/content-embed-kit-terminology#客户端oe对象)连接时的回调函数。 |
| OH\_ContentEmbed\_Extension\_RegisterOnObjectDetachFunc | 取消注册客户端OE对象连接时的回调函数。 |
| OH\_ContentEmbed\_Extension\_RegisterOnWriteToDataStreamFunc | 注册[服务端OE对象](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/content-embed-kit-terminology#服务端oe对象)写入[OE文档](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/content-embed-kit-terminology#oe文档)数据流时的回调函数。 |
| OH\_ContentEmbed\_Extension\_RegisterOnGetSnapshotFunc | 注册客户端OE对象请求获取OE文档快照时的回调函数。 |
| OH\_ContentEmbed\_Extension\_RegisterOnDoEditFunc | 注册客户端OE对象请求编辑OE文档时的回调函数。 |
| OH\_ContentEmbed\_Extension\_RegisterOnGetEditStatusFunc | 注册客户端OE对象请求OE文档编辑状态时的回调函数。 |
| OH\_ContentEmbed\_Extension\_RegisterOnGetCapabilityFunc | 注册客户端OE对象查询OE Extension实例支持能力时的回调函数。 |
| OH\_ContentEmbed\_Extension\_GetContentEmbedDocument | 获取服务端OE对象关联的OE文档实例。 |
| OH\_ContentEmbed\_Extension\_CallbackToOnUpdate | 触发客户端OE对象注册的OE文档更新回调函数。 |
| OH\_ContentEmbed\_Extension\_CallbackToOnError | 触发客户端OE对象注册的OE文档错误回调函数。 |
| OH\_ContentEmbed\_Extension\_CallbackToOnEditingFinished | 触发客户端OE对象注册的OE文档编辑完成回调函数。 |
| OH\_ContentEmbed\_Extension\_CallbackToOnExtensionStopped | 触发OE Extension关联的所有客户端OE对象注册的OE Extension停止时的回调函数。 |
| OH\_ContentEmbed\_Extension\_SetSnapshot | 设置客户端OE对象关联的OE文档快照图像。 |
| OH\_ContentEmbed\_Extension\_ContextStartSelfUIAbility | 通过OE Extension上下文启动自身的UIAbility。 |

#### 开发步骤

以下演示使用Native API开发OE服务端应用的完整流程，演示了OE服务端注册Extension组件回调，响应客户端请求，返回OE文档快照和启动UIAbility编辑OE文档。

#### \[h2\]OE服务端配置OE ExtensionAbility

从API version 24版本开始，在module.json5文件的extensionAbilities标签中配置OE ExtensionAbility，示例如下：

"extensionAbilities": \[
    {
        "name": "OEExtAbility",
        "srcEntry": "libentry.so",
        "type": "contentEmbed",
        "exported": true,
        "metadata": \[
            {
                "name": "content\_embed\_config",
                "resource": "$profile:content\_embed\_config"
            }
        \]
    }
\]

配置说明：

*   name：Extension组件的名称。
*   srcEntry：Extension组件的入口库文件路径。
*   type：必须设置为"contentEmbed"。
*   exported：必须设置为true，表示对外暴露。
*   [metadata](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/module-configuration-file#metadata标签)：元数据信息"metadata"新增一个"name"为"content\_embed\_config"的数据项，"resource"为OE Extension配置文件的资源索引。

开发者需要新增一个二级配置json文件，用于配置OE Extension信息。例如将"resource"配置成"$profile:content\_embed\_config"，表示指向resources/base/profile/content\_embed\_config.json配置文件。json文件示例如下：

{
    "content\_embed\_config": \[
        {
            "oeid": "E0A8B74A-445B-4D7A-8B05-07B5509B50D8",
            "file\_exts": ".doc|.docx",
            "icon": "$media:app\_logo",
            "name": "$string:name",
            "description": "$string:description"
        }
    \]
}

配置说明：

*   oeid：OE文档的系统可识别标识符，用于定位支持该OE文档的OE服务端应用。
    *   如果OE服务端应用在其它操作系统上也有相同功能，建议复用已在其它系统中使用的ID；
    *   如果OE服务端应用该功能仅在HarmonyOS系统上提供，则建议使用系统自带的“终端”工具，通过uuidgen命令生成新的ID。
*   file\_exts：支持的文件扩展名，如".doc"、".docx"等，如果支持多个文件后缀，使用"|"进行隔开。
*   icon：OE文档查询显示图标，取值为图标资源文件的索引。
*   name：OE文档查询显示名称，要求采用该名称的资源索引，以支持多语言。
*   description：OE文档查询显示描述，要求采用该名称的资源索引，以支持多语言。

#### \[h2\]添加动态链接库

CMakeLists.txt中添加以下lib。

\# content embed
libcontent\_embed\_ndk.so
# hilog
libhilog\_ndk.z.so
# ace
libace\_napi.z.so
# piexlmap
libpixelmap.so
# ability
libability\_runtime.so
# want
libability\_base\_want.so
# fileuri
libohfileuri.so
# libimage\_source
libimage\_source.so

#### \[h2\]导入头文件

#include <cstdint>
#include <fstream>
#include <hilog/log.h>
#include <AbilityKit/ability\_base/want.h>
#include <AbilityKit/ability\_runtime/application\_context.h>
#include <ContentEmbedKit/content\_embed/content\_embed\_document.h>
#include <ContentEmbedKit/content\_embed/content\_embed\_extension.h>
#include <filemanagement/file\_uri/oh\_file\_uri.h>
#include <multimedia/image\_framework/image/image\_source\_native.h>

#### \[h2\]定义全局变量

static ContentEmbed\_ExtensionInstanceHandle g\_instance = nullptr;

#### \[h2\]注册Extension回调函数

当OE服务端应用的OE Extension被系统启动以响应OE客户端请求时，首先执行[OH\_AbilityRuntime\_OnNativeExtensionCreate](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-extension-ability-h#oh_abilityruntime_onnativeextensioncreate)函数，需在该函数中注册OE Extension回调，以响应客户端请求。

extern "C" void OH\_AbilityRuntime\_OnNativeExtensionCreate(AbilityRuntime\_ExtensionInstance \*instance, const char \*abilityName) {
    if (instance == nullptr) {
        OH\_LOG\_ERROR(LOG\_APP, "instance is null");
        return;
    }

    ContentEmbed\_ExtensionInstanceHandle ceExtensionInstance;
    // 获取OE Extension实例
    ContentEmbed\_ErrorCode ret = OH\_ContentEmbed\_Extension\_GetExtensionInstance(instance, &ceExtensionInstance);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_GetExtensionInstance failed, errCode: %{public}d.", ret);
        return;
    }
    // 给全局变量赋值
    g\_instance = ceExtensionInstance;
    // 注册OE Extension创建函数回调
    ret = OH\_ContentEmbed\_Extension\_RegisterOnCreateFunc(ceExtensionInstance, NativeOnCreate);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnCreateFunc failed, errCode: %{public}d.", ret);
        return;
    }
    // 注册OE Extension销毁函数回调
    ret = OH\_ContentEmbed\_Extension\_RegisterOnDestroyFunc(ceExtensionInstance, NativeOnDestroy);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnDestroyFunc failed, errCode: %{public}d.", ret);
        return;
    }
    // 注册服务端OE对象绑定回调
    ret = OH\_ContentEmbed\_Extension\_RegisterOnObjectAttachFunc(ceExtensionInstance, RegisterOnObjectAttachFunc);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnObjectAttachFunc failed, errCode: %{public}d.", ret);
        return;
    }
    // 注册服务端OE对象解绑回调
    ret = OH\_ContentEmbed\_Extension\_RegisterOnObjectDetachFunc(ceExtensionInstance, RegisterOnObjectDetachFunc);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnObjectDetachFunc failed, errCode: %{public}d.", ret);
        return;
    }
}

#### \[h2\]实现创建和销毁生命周期回调函数

static void NativeOnCreate(ContentEmbed\_ExtensionInstanceHandle instance, AbilityBase\_Want \*want)
{
    OH\_LOG\_INFO(LOG\_APP, "enter NativeOnCreate");
}

static void NativeOnDestroy(ContentEmbed\_ExtensionInstanceHandle instance)
{
    OH\_LOG\_INFO(LOG\_APP, "enter NativeOnDestroy");
}

#### \[h2\]实现服务端OE对象绑定和解绑的回调函数

当OE客户端调用[OH\_ContentEmbed\_Proxy\_StartWork](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-proxy-h#oh_contentembed_proxy_startwork)函数将客户端OE对象与服务端OE对象绑定时，系统会触发OE服务端的RegisterOnObjectAttachFunc回调。在此回调中，OE服务端需调用服务端OE对象的注册函数以响应OE客户端的请求。

当OE客户端调用[OH\_ContentEmbed\_Proxy\_StopWork](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-proxy-h#oh_contentembed_proxy_stopwork)函数将客户端OE对象与服务端OE对象解除绑定时，系统会触发OE服务端的RegisterOnObjectDetachFunc回调，在该回调后服务端OE对象将失效。

static void RegisterOnObjectAttachFunc(ContentEmbed\_ExtensionInstanceHandle instance, ContentEmbed\_ObjectHandle object)
{
    ContentEmbed\_ErrorCode ret = CE\_ERR\_OK;
    // 当OE文档是通过文件创建的时候执行该回调函数
    ret = OH\_ContentEmbed\_Extension\_RegisterOnWriteToDataStreamFunc(object, NativeOnWriteToDataStream);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnWriteToDataStreamFunc failed, errCode: %{public}d.", ret);
        return;
    }
    // 获取当前OE Extension的能力
    ret = OH\_ContentEmbed\_Extension\_RegisterOnGetCapabilityFunc(object, NativeOnGetCapability);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnGetCapabilityFunc failed, errCode: %{public}d.", ret);
        return;
    }
    // OE文档触发编辑操作
    ret = OH\_ContentEmbed\_Extension\_RegisterOnDoEditFunc(object, NativeOnDoEdit);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnDoEditFunc failed, errCode: %{public}d.", ret);
        return;
    }
    // OE文档请求获取快照
    ret = OH\_ContentEmbed\_Extension\_RegisterOnGetSnapshotFunc(object, NativeOnGetSnapshot);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnGetSnapshotFunc failed, errCode: %{public}d.", ret);
        return;
    }
    // OE文档查询当前编辑状态
    ret = OH\_ContentEmbed\_Extension\_RegisterOnGetEditStatusFunc(object, NativeOnGetEditStatusFunc);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_RegisterOnGetEditStatusFunc failed, errCode: %{public}d.", ret);
        return;
    }
}

static void RegisterOnObjectDetachFunc(ContentEmbed\_ExtensionInstanceHandle instance, ContentEmbed\_ObjectHandle object)
{
    OH\_LOG\_INFO(LOG\_APP, "enter RegisterOnObjectDetachFunc");
}

#### \[h2\]实现获取OE文档快照

当OE客户端通过新建对象类型或已存在文件来嵌入OE对象时，OE对象在OE客户端界面中可能呈现为文档快照（Snapshot），当OE Extension被启动后，OE客户端会通过[OH\_ContentEmbed\_Proxy\_GetSnapshot](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-proxy-h#oh_contentembed_proxy_getsnapshot)获取文档快照，此时会触发OE服务端的NativeOnGetSnapshot回调，在该回调中OE服务端应用需调用[OH\_ContentEmbed\_Extension\_SetSnapshot](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-extension-h#oh_contentembed_extension_setsnapshot)设置OE文档快照。

static void NativeOnGetSnapshot(ContentEmbed\_ObjectHandle object)
{
    // 当前OE文档快照路径
    std::string path = "/data/storage/el2/base/haps/entry/temp/snapshot\_demo.png";
    // 判断当前是否有UI生成的缩略图
    FILE \*srcFile = fopen(path.c\_str(), "rb");
    if (!srcFile) {
        OH\_LOG\_ERROR(LOG\_APP, "文件打开失败");
        return;
    }
    int fd = fileno(srcFile);
    // 创建ImageSource实例。
    OH\_ImageSourceNative \*source = nullptr;
    Image\_ErrorCode errCode = OH\_ImageSourceNative\_CreateFromFd(fd, &source);
    if (errCode != IMAGE\_SUCCESS) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ImageSourceNative\_CreateFromFd failed, errCode: %{public}d.", errCode);
        return;
    }
    // 通过图片解码参数创建PixelMap对象。
    OH\_DecodingOptions \*ops = nullptr;
    OH\_DecodingOptions\_Create(&ops);
    // 设置为AUTO会根据图片资源格式解码，如果图片资源为HDR资源则会解码为HDR的pixelmap。
    OH\_DecodingOptions\_SetDesiredDynamicRange(ops, IMAGE\_DYNAMIC\_RANGE\_AUTO);
    OH\_PixelmapNative \*resPixMap = nullptr;

    // ops参数支持传入nullptr, 当不需要设置解码参数时，不用创建。
    errCode = OH\_ImageSourceNative\_CreatePixelmap(source, ops, &resPixMap);
    OH\_DecodingOptions\_Release(ops);
    if (errCode != IMAGE\_SUCCESS) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ImageSourceNative\_CreatePixelmap failed, errCode: %{public}d.", errCode);
        return;
    }
    // 设置快照
    ContentEmbed\_ErrorCode ret = OH\_ContentEmbed\_Extension\_SetSnapshot(object, resPixMap);
    // 释放ImageSource实例。
    OH\_ImageSourceNative\_Release(source);
}

#### \[h2\]实现编辑OE文档

当OE Extension被启动后，OE客户端会通过[OH\_ContentEmbed\_Proxy\_DoEdit](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-proxy-h#oh_contentembed_proxy_doedit)通知OE服务端编辑OE文档，此时会触发OE服务端的NativeOnDoEdit回调，在该回调中OE服务端应用需调用[OH\_ContentEmbed\_Extension\_ContextStartSelfUIAbility](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-extension-h#oh_contentembed_extension_contextstartselfuiability)或[OH\_ContentEmbed\_Extension\_ContextStartSelfUIAbilityWithStartOptions](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-extension-h#oh_contentembed_extension_contextstartselfuiabilitywithstartoptions)启动OE服务端应用的UIAbility编辑文档。

static void NativeOnDoEdit(ContentEmbed\_ObjectHandle object)
{
    ContentEmbed\_ErrorCode ret = CE\_ERR\_OK;
    ContentEmbed\_Document\* ceDocument;
    // 获取当前OE文档
    ret = OH\_ContentEmbed\_Extension\_GetContentEmbedDocument(object, &ceDocument);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_GetContentEmbedDocument failed, errCode: %{public}d.", ret);
        return;
    }
    // 获取当前上下文实例
    ContentEmbed\_ExtensionContextHandle context;
    ret = OH\_ContentEmbed\_Extension\_GetContentEmbedContext(g\_instance, &context);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_GetContentEmbedContext failed, errCode: %{public}d.", ret);
        return;
    }
    // 需要启动的UIAbility的信息
    char\* bundleName = "com.example.oeserverdemo"; // 服务端应用的包名
    char\* moduleName = "entry";
    char\* abilityName = "EntryAbility";
    // 创建Want对象
    AbilityBase\_Element element = {
        .bundleName = bundleName,
        .moduleName = moduleName,
        .abilityName = abilityName,
    };
    AbilityBase\_Want\* want = OH\_AbilityBase\_CreateWant(element);
    // 获取OE文档的RootStorage
    ContentEmbed\_Storage \*rootStorage = nullptr;
    ret = OH\_ContentEmbed\_Document\_GetRootStorage(ceDocument, &rootStorage);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Document\_GetRootStorage failed, errCode: %{public}d.", ret);
        return;
    }
    // 判断document中是否有指定stream
    ContentEmbed\_Stream \*childStream;
    char\* fileType = "aaa";
    ret = OH\_ContentEmbed\_Storage\_GetStream(rootStorage, fileType, &childStream);
    if (ret == CE\_ERR\_OK) {
        size\_t bufferSize;
        // 获取OE文档流的大小
        ret = OH\_ContentEmbed\_Stream\_GetSize(childStream, &bufferSize);
        if (ret != CE\_ERR\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Stream\_GetSize failed, errCode: %{public}d.", ret);
            return;
        }
        // Read之前需要将流位置重置
        ret = OH\_ContentEmbed\_Stream\_Seek(childStream, 0);
        if (ret != CE\_ERR\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Stream\_Seek failed, errCode: %{public}d.", ret);
            return;
        }
        unsigned char \*buffer;
        size\_t num = 0;
        // 读取流数据
        ret = OH\_ContentEmbed\_Stream\_Read(childStream, &buffer, bufferSize, &num);
        if (ret != CE\_ERR\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Stream\_Read failed, errCode: %{public}d.", ret);
            return;
        }
        std::string tempPath = "/data/storage/el2/base/cache/temp\_demo.aaa";
        // 创建输出文件流对象，并以二进制模式打开文件
        std::ofstream outputFile(tempPath, std::ios::out | std::ios::binary);
        // 检查文件是否成功打开
        if (outputFile.is\_open()) {
            // 将缓冲区内容写入文件
            outputFile.write(reinterpret\_cast<const char\*>(buffer), bufferSize);
            // 关闭文件（析构函数会自动调用，但显式关闭是好习惯）
            outputFile.close();
            OH\_LOG\_INFO(LOG\_APP, "数据写入成功.");
        } else {
            OH\_LOG\_INFO(LOG\_APP, "无法打开文件.");
        }
        char\* tempFileUri;
        OH\_FileUri\_GetUriFromPath(tempPath.c\_str(), tempPath.size(), &tempFileUri);
        // 设置文件路径
        OH\_AbilityBase\_SetWantUri(want, tempFileUri);
    }
    // 启动UIAbility 对文档进行编辑操作
    ret = OH\_ContentEmbed\_Extension\_ContextStartSelfUIAbility(context, want);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_ERROR(LOG\_APP, "OH\_ContentEmbed\_Extension\_ContextStartSelfUIAbility failed, errCode: %{public}d.", ret);
        return;
    }
}

#### \[h2\]实现获取OE Extension能力

当OE Extension被启动后，OE客户端会通过[OH\_ContentEmbed\_Proxy\_GetCapability](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-proxy-h#oh_contentembed_proxy_getcapability)获取OE服务端具备的能力，此时会触发OE服务端的NativeOnGetCapability回调，在该回调中OE服务端应用通过给bitmask属性赋值，通知OE客户端自身具备的能力。

static void NativeOnGetCapability(ContentEmbed\_ObjectHandle object, uint32\_t \*bitmask)
{
    if (!bitmask) {
        OH\_LOG\_ERROR(LOG\_APP, "bitmask is null");
        return;
    }
    \*bitmask = CE\_CAPABILITY\_SUPPORT\_SNAPSHOT | CE\_CAPABILITY\_SUPPORT\_DO\_EDIT;
}

#### \[h2\]实现查询OE文档编辑状态

当OE Extension被启动后，OE客户端会通过[OH\_ContentEmbed\_Proxy\_GetEditStatus](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-content-embed-proxy-h#oh_contentembed_proxy_geteditstatus)获取OE文档编辑状态，此时会触发OE服务端的NativeOnGetEditStatusFunc回调，在该回调中OE服务端应用通知OE客户端文档编辑状态。

static void NativeOnGetEditStatusFunc(ContentEmbed\_ObjectHandle object, bool \*isEditing, bool \*isModified)
{
    if (!isEditing || !isModified) {
        OH\_LOG\_ERROR(LOG\_APP, "param is null");
        return;
    }
    // 若文档未处于编辑态
    \*isEditing = false;
    \*isModified = false;
}

#### \[h2\]实现OE文档写流操作

当OE客户端通过已存在文件来嵌入OE对象且OE Extension被启动后，此时会触发OE服务端的NativeOnWriteToDataStream回调，在该回调中OE服务端需往OE文档中写入数据。

static void NativeOnWriteToDataStream(ContentEmbed\_ObjectHandle object)
{
    ContentEmbed\_ErrorCode ret = CE\_ERR\_OK;
    ContentEmbed\_Document\* ceDocument = nullptr;
    // 获取OE文档
    ret = OH\_ContentEmbed\_Extension\_GetContentEmbedDocument(object, &ceDocument);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_INFO(LOG\_APP, "OH\_ContentEmbed\_Extension\_GetContentEmbedDocument ret: %{public}d", ret);
        return;
    }
    // 获取Root Storage
    ContentEmbed\_Storage \*rootStorage = nullptr;
    ret = OH\_ContentEmbed\_Document\_GetRootStorage(ceDocument, &rootStorage);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_INFO(LOG\_APP, "OH\_ContentEmbed\_Document\_GetRootStorage ret: %{public}d", ret);
        return;
    }

    ContentEmbed\_Stream \*destStream;
    char\* fileType = "aaa";
    // 获取名字为aaa的流
    ret = OH\_ContentEmbed\_Storage\_GetStream(rootStorage, fileType, &destStream);
    if (ret != CE\_ERR\_OK) {
        // 获取失败创建名字为aaa的流
        ret = OH\_ContentEmbed\_Storage\_CreateStream(rootStorage, fileType, &destStream);
    }
    // 获取本地文件路径
    char nativeFilePath\[MAX\_PATH\_LENGTH\];
    ret = OH\_ContentEmbed\_Document\_GetNativeFilePath(ceDocument, nativeFilePath);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_INFO(LOG\_APP, "OH\_ContentEmbed\_Document\_GetNativeFilePath ret: %{public}d", ret);
        return;
    }

    std::string srcStreamPath = std::string(nativeFilePath);
    std::ifstream oriFile(srcStreamPath, std::ios::binary);
    if (!oriFile) {
        OH\_LOG\_ERROR(LOG\_APP, "File not found");
        return;
    }
    oriFile.seekg(0, std::ios::end);
    size\_t oriFileSize = oriFile.tellg();
    oriFile.seekg(0, std::ios::beg);
    std::vector<unsigned char> buffer(oriFileSize);
    oriFile.read(reinterpret\_cast<char\*>(buffer.data()), oriFileSize);
    size\_t num = 0;
    // 往OE文档写数据
    ret = OH\_ContentEmbed\_Stream\_Write(destStream, buffer.data(), oriFileSize, &num);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_INFO(LOG\_APP, "OH\_ContentEmbed\_Stream\_Write ret: %{public}d", ret);
        return;
    }
    // 刷新OE文档
    ret = OH\_ContentEmbed\_Document\_Flush(ceDocument);
    if (ret != CE\_ERR\_OK) {
        OH\_LOG\_INFO(LOG\_APP, "OH\_ContentEmbed\_Document\_Flush ret: %{public}d", ret);
        return;
    }
}