as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
AWS
文档
Support
Contact Us
My Cases
新手入门
设计和开发
应用发布
参考
支持

原生代码中的JavaScript类型

原生代码中的JavaScript类型

Vega Turbo模块支持各种原生类型,这些类型可以在Turbo模块参数和返回值中与JavaScript相互转换。这意味着,例如,可以使用JavaScript字符串从JavaScript调用接受std::string的Turbo模块方法,该参数将被自动转换;同样,返回std::string的Turbo模块方法将向JavaScript环境返回JavaScript字符串。其中一些类型(例如std::stringint32_t)是基本的C++类型。其他类型是Vega特有的,大多存在于com::amazon::kepler::turbomodule命名空间中。

类型映射

下表显示了TypeScript类型与其C++对应类型之间的映射。这是codegen工具使用的映射。

其中一些类型不是基本TypeScript的一部分,需要从@amazon-devices/keplerscript-turbomodule-api导入。

TypeScript类型 原生类型
string std::string
number double
Int32 int32_t
UInt32 uint32_t
Int64[1] int64_t
Double double
Float float
boolean bool
void void
Array<T>, T[] (homogeneous)[2] std::vector<T>
Array JSArray
Object JSObject
Promise Promise
Function(参数类型) Callback
Function(返回类型) HostCallback
bigint BigInt[3]
ArrayBuffer ArrayBuffer
NativeObject std::shared_ptr<NativeObject>
*JsonContainer[4] utils::json::JsonContainer

[1] int64_t可能因Number.MAX_SAFE_INTEGER发生精度损失。对于有精度要求的大整数,您可以使用BigInt

[2] 同构数组是指其元素类型相同的数组。

[3] 对于有符号和无符号的64位整数,都支持将BigInt用作直接方法参数和返回类型。有关支持的用法的更多详细信息,请参阅BigInt

[4] JSObject的差距得到解决后,JsonContainer将被删除。如果需要使用该类型,可以从泛型Object@amazon-devices/keplerscript-turbomodule-api中导入JsonContainer类型,也可定义自定义类型别名,例如:

已复制到剪贴板。

type MyJsonContainer = {myProperty: string};

注意:​ 对于大于JavaScript的Number.MAX_SAFE_INTEGER的整数,使用std::string表示形式来表示Turbo模块的参数和返回类型。您可以在JavaScript和C++实现中将字符串转换为更合适的类型。

JSArray

对于同构 (T[]) 数组,您可以使用std::vector<T>。对于其他数组,可以使用JSArray

JSArray是一个std::vector,它接受各种元素类型,包括空指针、布尔值、各种intdoublefloatstd::stringJSArrayJSObject。因此,它的用法类似于std::vector

示例

已复制到剪贴板。

JSArray SampleTurboModule::getJSArray() {
    auto jsObject = JSObject{};
    auto jsArray = JSArray{};

    jsArray.emplace_back(jsObject);
    jsArray.emplace_back(std::string{"foo"});
    jsArray.emplace_back(3.14);

    return jsArray;
}

JSArray SampleTurboModule::extendJSArray(JSArray arr) {
  arr.emplace_back(std::string{"新元素"});
  return arr;
}

JSObject

JSObject是一个带有std::string键的std::map,它接受各种值类型,包括空指针、布尔值、各种intdoublefloatstd::stringJSArrayJSObject。因此,它的用法类似于std::map

JSObject提供了一种静态parseJson方法。parseJson方法接受std::string JSON字符串并返回等效的JSObject

示例

已复制到剪贴板。

JSObject SampleTurboModule::getJSObject(std::string jsonContent) {
    auto jsObject = JSObject::parseJson(jsonContent);
    return jsObject;
}

JSObject SampleTurboModule::getJSObject() {
    auto jsObject = JSObject{};

    jsObject.emplace("intValue", 100);
    jsObject.emplace("doubleValue", 25.1);
    jsObject.emplace("boolValue", true);
    jsObject.emplace("strValue", std::string{"字符串值"});

    return jsObject;
}

JSObject SampleTurboModule::extendJSObject(JSObject obj) {
    obj.emplace("foo", std::string{"bar"});
    return obj;
}

代理JSObject和JSArray

除了JSObjectJSArray类型外,Vega Turbo模块还支持代理类型proxy::JSObjectproxy::JSArray。代理类型的关键功能之一是动态访问和修改。您可以直接使用C++代码对JavaScript对象和数组进行读取和写入,而不必创建副本。

但是,在使用这些代理类型时,请谨记以下的重要事项:

  • 线程注意事项:

    代理类型必须在JSThread上下文和Turbo模块方法调用的范围内使用。这些类型不能从任意线程存储或访问。线程安全检查仅在调试模式下执行。因此,在多线程环境中使用这些代理对象时需要小心。

  • 原生结构:

    虽然您可以在本地构造新的代理项目,但您需要利用Turbo模块或HostCallback方法获取所需的JSRuntime作为方法参数。

    警告: 请勿使用默认的构造函数。这些代理类型的默认构造函数仅用于支持std::tuplestd::variant等结构中的当前内部用法。您不应该依赖这些默认的构造函数,因为它们需要JSThread上下文,并且在未来的版本中将会被删除。

JSRuntime

JSRuntime类型表示JavaScript运行时环境。它是一种仅限原生的类型,任何Turbo模块或HostCallback方法都可以将其作为参数进行调用。它通常用于在C++中创建新的代理项目。

注意:​ JSRuntime无法从非JSThread进行构造。

已复制到剪贴板。

void SampleTurboModuleV2::sampleMethod(JSRuntime rt) {
    // 创建新的代理对象
    auto newObject = proxy::JSObject(rt);

    // 创建代理数组
    auto newArray = proxy::JSArray(rt);
}

proxy::JSObject

借助proxy::JSObject类型,您不仅可以创建可以传递到原生代码的JavaScript对象,还可以从本机端动态访问和修改其属性和方法,而无需创建副本。

注意:​ 对proxy::JSObject的访问仅限于JSThread上下文,并且必须在Turbo模块方法调用的范围内进行。线程安全检查仅在调试模式下执行。

已复制到剪贴板。

std::vector<proxy::JSObject> SampleTurboModuleV2::getProxyObject(JSRuntime rt, std::vector<proxy::JSObject> args) {
    // 从接收到的对象读取属性
    auto object = args[0];
    auto propertyNames = object.getPropertyNames();
    for (const auto& propertyName: propertyNames) {
        auto propertyValue = object.getProperty(propertyName);
        if (std::holds_alternative<std::string>(propertyValue)) {
            auto stringValue = std::get<std::string>(propertyValue);
            TMINFO("Property " + propertyName + " = " + stringValue);
        }
    }

    // 创建并返回新对象
    auto newObject = proxy::JSObject(rt);
    newObject.setProperty("stringProp", "foo");
    newObject.setProperty("numberProp", 1.5);
    newObject.setProperty("boolProp", true);

    args[0] = newObject;
    return args;
}

proxy::JSArray

借助proxy::JSArray类型,您可以创建支持传递到原生代码的JavaScript数组,并从本机端动态访问和修改其元素。

注意:​ 对proxy::JSArray的访问仅限于JSThread上下文,并且必须在Turbo模块方法调用的范围内进行。线程安全检查仅在调试模式下执行。

已复制到剪贴板。

proxy::JSArray SampleTurboModuleV2::getProxyArray(proxy::JSArray arg) {
    size_t index = 0;
    for(const auto& element: arg) {
        if (std::holds_alternative<std::string>(element)) {
            auto elementValue = std::get<std::string>(element);
            TMDEBUG("SampleTurboModuleV2::getProxyArray initial string element = " + elementValue);
            arg.set(index, "C++String");
        }
        ++index;
    }
    return arg;
}

Promise

应该在单独的线程上执行Promise。

Promise是使用PromiseOperation作为输入来构造的。PromiseOperation是接受std::shared_ptr<Promise>并返回void的函数。

Promiseresolvereject方法。可以使用Errorstd::string来拒绝Promise,并使用类型映射中的任何C++ Turbo模块类型来解析。

示例

已复制到剪贴板。

Promise<std::string> SampleTurboModule::getValueWithPromise(bool error) {
    return Promise([self = this, error](const std::shared_ptr<Promise>& promise) {
        std::thread([error, promise]() {
            if (error) {
                promise->reject(Error("用Error类拒绝了promise"));
            } else {
                promise->resolve(std::string{"结果"});
            }
        }).detach();;
    });
}

Callback

应该在单独的线程上执行回调。

Callback对象只能是参数值,代表传递给C++的JavaScript回调。有关作为返回类型的Callback的信息,请参见HostCallback

Callback对象公开的唯一方法是invoke,它使用指定的参数调用JavaScript回调,并将结果返回给C++。

示例

已复制到剪贴板。

// JS
SampleTurboModule.getValueWithCallback((value : number) => {
    console.log(value); // 这里显示的值是5,该值是通过C++的Callback.invoke方法作为参数传入的。
    return 2 * value;
});

// C++
void SampleTurboModule::getValueWithCallback(Callback callback) {
    std::thread([](Callback callback) {
        auto future = callback.invoke(5);
        std::string returnValue{"undefined"};
        try {
         auto jsValue = future.get();
         // 从JS返回的任何数字始终是双精度类型
         if(std::holds_alternative<double>(jsValue)) {
           returnValue = std::to_string(std::get<double>(jsValue));
         }
        } catch (const std::exception& ex) {
         TMERROR("Error getting the return value from callback.Exception: " + std::string(ex.what()));
        }
        TMINFO("Return value from callback is: " + returnValue);
    }, callback).detach();
} 

HostCallback

HostCallback只能是一个返回值,用于向JavaScript环境返回C++回调。有关参数类型的回调,请参见Callback

示例

已复制到剪贴板。

// C++
std::string sampleHostCallbackMethod(std::string jsInputString) {
    return "Received JS string " + jsInputString);
}

HostCallback SampleTurboModule::getHostCallback() {
    return HostCallback(sampleHostCallbackMethod);
}

// JS
const hostCallback = SampleTurboModule.getHostCallback();
console.log(hostCallback("Hello from HostCallback!")); // 输出“received JS string Hello from HostCallback!”(收到JS字符串Hello from HostCallback!)
}

您也可以使用HostCallback来调用Callback

已复制到剪贴板。

// JS
SampleTurboModule.invokeCallbackWithHostCallback((hostCallback: (obj: Object) => number): void {
    const secret = hostCallback();
    console.log(secret); // logs 17
});

// C++
void SampleTurboModule::invokeCallbackWithHostCallback(Callback callback) {
    auto secret = 17;
    auto lambda = [secret]() {
        return secret;
    };
    auto hostCallback = HostCallback(std::function<int()>(lambda));

    callback.invoke(hostCallback);
}

ArrayBuffer

ArrayBuffer表示通用、固定长度的原始二进制数据缓冲区。

示例

已复制到剪贴板。

ArrayBuffer SampleTurboModule::getNativeMemoryArrayBuffer() {
    return {"Hello World!"};
}

ArrayBuffer SampleTurboModule::modifyArrayBuffer(ArrayBuffer buf) {
    // 没有数据副本,因为它只是在不插入新内容的情况下进行修改。
    uint8_t* data = buf.data();
    size_t size = buf.size();
    for (auto i = 0; i < size; i++) {
        data[i] = 9;
    }

    return buf;
}

ArrayBuffer SampleTurboModule::insertSecretData(ArrayBuffer buf) {
    // 在此处插入会创建数据副本并附加终结器
    uint8_t secret[] = {6, 7, 9, 9, 0};
    arg.insert(5, secret);
    return arg;
}

BigInt

一个BigInt代表一个整数。在JavaScript中,BigInt用于表示超过Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER的整数。在Vega中,Turbo模块支持通过基于int64_tuint64_t的getter和constructor方法表示BigInt

已复制到剪贴板。

BigInt SampleTurboModule::getBigInt(BigInt bigint) {
    // 创建BigInt
    auto big1 = BigInt::fromI64(-9007199254740990);
    auto big2 = BigInt::fromUi64(static_cast<uint64_t>(9007199254740990));

    // 访问值。Getter不依赖于构造中使用的类型。
    auto asI64 = bigint.getI64();
    auto asUi64 = bigint.getUi64();

    // getI64() 返回具有以下属性的结构
    int64_t i64value = asI64.value;
    bool lossless = asI64.lossless;

    // getUi64() 返回具有以下属性的结构
    bool is_signed = asUi64.is_signed;
    uint64_t ui64value = asUi64.value;
    bool lossless = asUi64.lossless;

    return big1;
}

您可以在方法参数和返回类型以及回调和Promise中使用BigInt,但只能作为原始值,不能作为JSArrayJSObject的一部分。

如果JavaScript BigInt过大而无法用Vega Turbo模块BigInt类型表示(例如无法用int64_tuint64_t表示),则会触发断言失败,Vega Turbo模块的所有无效参数也是如此。有关更多信息,请参阅“高级Turbo模块主题”中的错误处理

utils::json::JsonContainer

将不再把JsonContainer用于JSObject类型,但目前仍存在一些功能缺口。有关支持类型的完整列表,请参阅类型映射

示例

已复制到剪贴板。

utils::json::JsonContainer SampleTurboModuleV2::getJsonContainer() {
    auto result = utils::json::JsonContainer::createJsonObject();
    result.insert("const1", true);
    result.insert("const2", 375);
    result.insert("const3", std::string("something"));
    return result;
}

NativeObject

在大多数情况下,当您将数据从原生代码传递给JavaScript时,一个JSONContainerJSObject便足以满足需求。但是,如果您需要一个可以从JavaScript调用其方法的原生对象,您需要创建一个实现com::amazon::kepler::turbomodule::NativeObject的对象。

示例

已复制到剪贴板。

#include <Vega/turbomodule/NativeObject.h>

using namespace com::amazon::kepler::turbomodule;

class SampleNativeObject : NativeObject {
public:
    // 必须将方法添加到此函数中的methodAggregator中才能公开给JavaScript。
    void aggregateMethods(MethodAggregator<NativeObject> &methodAggregator) noexcept override {
        methodAggregator.addMethod("getString", 1,
                                   &SampleNativeObjectV2::getString);
    }
    std::string getString(std::string arg) {
        return "再见 " + arg;
    }
};

// 在TurboModule实现中:
std::shared_ptr<NativeObject> SampleTurboModule::getNativeObject() {
    return std::make_shared<SampleNativeObject>();
}

// 在JavaScript中使用:
SampleTurboModule.getNativeObject().getString("foo"); // 返回“Goodbye foo”

请注意,仅支持将NativeObject作为Turbo模块方法返回类型,而不支持将其作为参数。

APMF类型

IDL使用某些APMF类型,这些类型并不总是可以在支持的Turbo模块参数/返回类型之间直接转换。您可能需要实现自定义逻辑才能进行这些转换。

创建Turbo模块


Last updated: 2025年9月30日