diff --git a/en/application-dev/quick-start/ffi-napi-introduction.md b/en/application-dev/quick-start/ffi-napi-introduction.md new file mode 100644 index 0000000000000000000000000000000000000000..d8d6fb3d96812091974d234411951221d6c5e9e8 --- /dev/null +++ b/en/application-dev/quick-start/ffi-napi-introduction.md @@ -0,0 +1,10 @@ +# FFI Capability (N-API) +## N-APIs Supported by ArkUI-X +Node-APIs provide a set of Native interfaces that encapsulate the underlying JavaScript runtime capabilities. The OpenHarmony N-API component re-implements the Node-APIs. ArkUI-X also has this capability and supports [some interfaces](../reference/native-lib/third_party_napi/napi.md). + +## Application Scenarios of N-APIs in ArkUI-X +In OpenHarmony, the N-APIs implement interaction between ArkTS/TS/JS and C/C++ (Native). ArkUI-X extends the N-APIs across platforms. You can use N-API capabilities on OpenHarmony, HarmonyOS, Android, and iOS platforms to complete cross-language project development. The typical application scenarios of N-APIs in ArkUI-X are the same as those in OpenHarmony. That is, you can: +1. Use N-APIs to encapsulate Native capabilities and expose the interfaces to the ArkTS/TS/JS layer, to make ArkTS/TS/JS call Native APIs. +2. Call the methods provided by ArkTS/TS/JS in Native code, that is, make Native APIs call ArkTS/TS/JS. + +For details about how to develop a Native project on ArkUI-X, see [How to Use N-APIs on Android](../tutorial/how-to-use-napis-on-android.md) and [How to Use N-APIs on iOS](../tutorial/how-to-use-napis-on-ios.md). diff --git a/en/application-dev/reference/native-apis/Readme-EN.md b/en/application-dev/reference/native-apis/README.md old mode 100755 new mode 100644 similarity index 71% rename from en/application-dev/reference/native-apis/Readme-EN.md rename to en/application-dev/reference/native-apis/README.md index ab2b2b2bea70d1497e0d3eac12c81bea52752f21..c5af1186107d477728722e84a1209c35d746479b --- a/en/application-dev/reference/native-apis/Readme-EN.md +++ b/en/application-dev/reference/native-apis/README.md @@ -1,8 +1,10 @@ -# Native APIs +# Native API - Modules + - [Plugin Utils](_plugin_utils.md) - [Rawfile](rawfile.md) - Header Files + - [plugin_utils.h](plugin__utils_8h.md) - [raw_dir.h](raw__dir_8h.md) - [raw_file_manager.h](raw__file__manager_8h.md) - [raw_file.h](raw__file_8h.md) diff --git a/en/application-dev/reference/native-lib/third_party_napi/napi.md b/en/application-dev/reference/native-lib/third_party_napi/napi.md new file mode 100644 index 0000000000000000000000000000000000000000..4acd8a17e37715e3e2ba2eeffc03af1a3099e41e --- /dev/null +++ b/en/application-dev/reference/native-lib/third_party_napi/napi.md @@ -0,0 +1,148 @@ +# Node-API + +## Overview + +Node-APIs provide a set of Native interfaces that encapsulate the underlying JavaScript runtime capabilities. + +## Supported Capabilities + +Node-APIs shield the differences between different underlying JavaScript engines and provide a set of stable interfaces. + +The OpenHarmony N-API component re-implements Node-APIs. ArkUI-X extends N-APIs across platforms to enable N-APIs to be used on OpenHarmony, HarmonyOS, Android, and iOS. The following table lists the supported interfaces in the [Node-API standard library](https://nodejs.org/docs/v14.9.0/api/n-api.html). + +## Extended Symbols of the N-API Component + +**Symbols Exported from the Node-API Library** + +|Type|Symbol|Description| +| --- | --- | --- | +|FUNC|napi_module_register|Registers the NAPI native module.| +|FUNC|napi_get_last_error_info|Obtains the **napi_extended_error_info** struct, which contains the latest error information.| +|FUNC|napi_throw|Throws a JS value.| +|FUNC|napi_throw_error|Throws a JS **Error** with text information.| +|FUNC|napi_throw_type_error|Throws a JS **TypeError** with text information.| +|FUNC|napi_throw_range_error|Throws a JS **RangeError** with text information.| +|FUNC|napi_is_error|Checks whether **napi_value** indicates an error object.| +|FUNC|napi_create_error|Creates a JS **Error** with text information.| +|FUNC|napi_create_type_error|Creates a JS **TypeError** with text information.| +|FUNC|napi_create_range_error|Creates a JS **RangeError** with text information.| +|FUNC|napi_get_and_clear_last_exception|Obtains and clears the latest exception.| +|FUNC|napi_is_exception_pending|Checks whether an exception occurs.| +|FUNC|napi_fatal_error|Raises a fatal error to terminate the process immediately.| +|FUNC|napi_open_handle_scope|Creates a context environment.| +|FUNC|napi_close_handle_scope|Closes the input context. After the context is closed, all **napi_values** declared in it will be reclaimed.| +|FUNC|napi_open_escapable_handle_scope|Creates an escapable handle scope, from which the declared values can be returned to the parent scope.| +|FUNC|napi_close_escapable_handle_scope|Closes the escapable handle scope passed in.| +|FUNC|napi_escape_handle|Promotes the handle to the input JS object so that it is valid for the lifespan of its parent scope.| +|FUNC|napi_create_reference|Creates a reference for **napi_value** to improve the JS object lifecycle. The caller needs to manage the reference lifespan.| +|FUNC|napi_delete_reference|Deletes the reference passed in.| +|FUNC|napi_reference_ref|Increments the reference count for the reference passed in and returns the count.| +|FUNC|napi_reference_unref|Decrements the reference count for the reference passed in and returns the count.| +|FUNC|napi_get_reference_value|Obtains the JS **Object** associated with the reference.| +|FUNC|napi_create_array|Creates a JS **Array**.| +|FUNC|napi_create_array_with_length|Creates a JS **Array** of the specified length.| +|FUNC|napi_create_arraybuffer|Creates a JS **ArrayBuffer** of the specified size.| +|FUNC|napi_create_external|Allocates a JS value with external data.| +|FUNC|napi_create_external_arraybuffer|Allocates a JS **ArrayBuffer** with external data.| +|FUNC|napi_create_object|Creates a default JS **Object**.| +|FUNC|napi_create_symbol|Create a JS **Symbol**.| +|FUNC|napi_create_typedarray|Creates a JS **TypeArray** from an existing **ArrayBuffer**.| +|FUNC|napi_create_dataview|Creates a JS **DataView** from an existing **ArrayBuffer**.| +|FUNC|napi_create_int32|Creates a JS **Number** from C **int32_t** data.| +|FUNC|napi_create_uint32|Creates a JS **Number** from C **uint32_t** data.| +|FUNC|napi_create_int64|Creates a JS **Number** from C **int64_t** data.| +|FUNC|napi_create_double|Creates a JS **Number** from C **double** data.| +|FUNC|napi_create_string_latin1|Creates a JS **String** from an ISO-8859-1-encoded C string.| +|FUNC|napi_create_string_utf8|Creates a JS **String** from a UTF8-encoded C string.| +|FUNC|napi_create_string_utf16|Creates a JS **String** from a UTF16-encoded C string.| +|FUNC|napi_get_array_length|Obtains the length of an array.| +|FUNC|napi_get_arraybuffer_info|Obtains the underlying data buffer of the **ArrayBuffer** and its length.| +|FUNC|napi_get_prototype|Obtains the prototype of the specified JS **Object**.| +|FUNC|napi_get_typedarray_info|Obtains properties of the specified **TypedArray**.| +|FUNC|napi_get_dataview_info|Obtains properties of the specified **DataView**.| +|FUNC|napi_get_value_bool|Obtains the C Boolean equivalent of the given JS **Boolean**.| +|FUNC|napi_get_value_double|Obtains the C double equivalent of the given JS **Number**.| +|FUNC|napi_get_value_external|Obtains the external data pointer previously passed through **napi_create_external()**.| +|FUNC|napi_get_value_int32|Obtains the C int32 equivalent of the given JS **Number**.| +|FUNC|napi_get_value_int64|Obtains the C int64 equivalent of the given JS **Number**.| +|FUNC|napi_get_value_string_latin1|Obtains the ISO-8859-1-encoded string corresponding to the given JS value.| +|FUNC|napi_get_value_string_utf8|Obtains the UTF8-encoded string corresponding to the given JS value.| +|FUNC|napi_get_value_string_utf16|Obtains the UTF16-encoded string corresponding to the given JS value.| +|FUNC|napi_get_value_uint32|Obtains the C uint32 equivalent of the given JS **Number**.| +|FUNC|napi_get_boolean|Obtains the JS Boolean object based on the given C Boolean value.| +|FUNC|napi_get_global|Obtains the **global** object.| +|FUNC|napi_get_null|Obtains the **null** object.| +|FUNC|napi_get_undefined|Obtains the **undefined** object.| +|FUNC|napi_coerce_to_bool|Forcibly converts the given JS value to a JS Boolean value.| +|FUNC|napi_coerce_to_number|Forcibly converts the given JS value to a JS number.| +|FUNC|napi_coerce_to_object|Forcibly converts the given JS value to a JS object.| +|FUNC|napi_coerce_to_string|Forcibly converts the given JS value to a JS string.| +|FUNC|napi_typeof|Obtains the JS type of the given JS value.| +|FUNC|napi_instanceof|Checks whether the given object is an instance of the specified constructor.| +|FUNC|napi_is_array|Checks whether the given JS value is an array.| +|FUNC|napi_is_arraybuffer|Checks whether the given JS value is a ArrayBuffer.| +|FUNC|napi_is_typedarray|Checks whether the given JS value is a **TypedArray**.| +|FUNC|napi_is_dataview|Checks whether the given JS value is a **DataView**.| +|FUNC|napi_is_date|Checks whether the given JS value is a JS **Date** object.| +|FUNC|napi_strict_equals|Checks whether two JS values are strictly equal.| +|FUNC|napi_get_property_names|Obtains the names of the enumerable properties of **Object** in an array of strings.| +|FUNC|napi_set_property|Sets a property for the given **Object**.| +|FUNC|napi_get_property|Obtains the requested property of the given **Object**.| +|FUNC|napi_has_property|Checks whether the given **Object** has the specified property.| +|FUNC|napi_delete_property|Deletes the **key** property from the given **Object**.| +|FUNC|napi_has_own_property|Checks whether the given **Object** has the own property named **key**.| +|FUNC|napi_set_named_property|Sets a property with the specified name for the given **Object**.| +|FUNC|napi_get_named_property|Obtains the property with the specified name in the given **Object**.| +|FUNC|napi_has_named_property|Checks whether the given **Object** has the property with the specified name.| +|FUNC|napi_set_element|Sets an element at the specified index of the given **Object**.| +|FUNC|napi_get_element|Obtains the element at the specified index of the given **Object**.| +|FUNC|napi_has_element|Obtains the element if the given **Object** has an element at the specified index.| +|FUNC|napi_delete_element|Deletes the element at the specified index of the given **Object**.| +|FUNC|napi_define_properties|Defines multiple properties for the given **Object**.| +|FUNC|napi_type_tag_object|Associates the value of the tag pointer with **Object**.| +|FUNC|napi_check_object_type_tag|Checks whether a tag pointer is associated with the JS **Object**.| +|FUNC|napi_call_function|Calls a JS function in a Native method, that is, Native calls JS.| +|FUNC|napi_create_function|Creates a Native method for JS to call.| +|FUNC|napi_get_cb_info|Obtains detailed information about the call, such as the parameters and **this** pointer, from the given callback info.| +|FUNC|napi_get_new_target|Obtains the **new.target** of the constructor call.| +|FUNC|napi_new_instance|Creates an instance based on the given constructor.| +|FUNC|napi_define_class|Defines a JS class corresponding to the C++ class.| +|FUNC|napi_wrap|Wraps a Native instance in a JS object.| +|FUNC|napi_unwrap|Obtains the Native instance that was previously wrapped in a JS object.| +|FUNC|napi_remove_wrap|Obtains the Native instance that was previously wrapped in a JS object and removes the wrapping.| +|FUNC|napi_create_async_work|Creates a work object that executes logic asynchronously.| +|FUNC|napi_delete_async_work|Releases an asynchronous work object.| +|FUNC|napi_queue_async_work|Adds an asynchronous work object to the queue so that it can be scheduled for execution.| +|FUNC|napi_cancel_async_work|Cancels the queued asynchronous work if it has not been started.| +|FUNC|napi_get_node_version|Obtains the current Node-API version.| +|FUNC|napi_get_version|Obtains the latest Node-API version supported when the Node.js runtime.| +|FUNC|napi_create_promise|Creates a deferred object and a JS promise.| +|FUNC|napi_resolve_deferred|Resolves a deferred object that is associated with a JS promise.| +|FUNC|napi_reject_deferred|Rejects a deferred object that is associated with a JS promise.| +|FUNC|napi_is_promise|Checks whether the given JS value is a promise object.| +|FUNC|napi_get_uv_event_loop|Obtains the current libuv loop instance.| +|FUNC|napi_create_threadsafe_function|Creates a thread-safe function.| +|FUNC|napi_get_threadsafe_function_context|Obtains the context of a thread-safe function.| +|FUNC|napi_call_threadsafe_function|Calls a thread-safe function.| +|FUNC|napi_acquire_threadsafe_function|Indicates that a thread starts to use a thread-safe function.| +|FUNC|napi_release_threadsafe_function|Indicates that a thread releases a thread-safe function.| +|FUNC|napi_ref_threadsafe_function|Indicates that the event loop running on the main thread should not exit until the thread-safe function is destroyed.| +|FUNC|napi_unref_threadsafe_function|Indicates that the event loop running on the main thread may exit before the thread-safe function is destroyed.| +|FUNC|napi_create_date|Creates a JS **Date** from C **double** data.| +|FUNC|napi_get_date_value|Obtains the C double equivalent of the given JS **Date**.| +|FUNC|napi_create_bigint_int64|Creates a JS **BigInt** from C **int64** data.| +|FUNC|napi_create_bigint_uint64|Creates a JS **BigInt** from C **uint64** data.| +|FUNC|napi_create_bigint_words|Creates a single JS **BigInt** from a C **uint64** array.| +|FUNC|napi_get_value_bigint_int64|Obtains the C **int64** equivalent of the given JS **BigInt**.| +|FUNC|napi_get_value_bigint_uint64|Obtains the C **uint64** equivalent of the given JS **BigInt**.| +|FUNC|napi_get_value_bigint_words|Obtains information from the given JS **BigInt**, including the sign bit, 64-bit little-endian array, and number of elements in the array.| +|FUNC|napi_create_buffer|Creates a JS **Buffer** instance of the specified size.| +|FUNC|napi_create_buffer_copy|Creates a JS **Buffer** instance of the specified size, and initializes it with data copied from the passed-in buffer.| +|FUNC|napi_create_external_buffer|Creates a JS **Buffer** instance of the specified size, and initializes it with the given data. The **Buffer** instance created can include extra.| +|FUNC|napi_get_buffer_info|Obtains the underlying data of **Buffer** and its length.| +|FUNC|napi_is_buffer|Checks whether the given JS value is a **Buffer** object.| +|FUNC|napi_object_freeze|Freezes the given object.| +|FUNC|napi_object_seal|Seals the given object.| +|FUNC|napi_get_all_property_names|Obtains an array containing the names of all the available properties of this object.| +|FUNC|napi_detach_arraybuffer|Detaches the underlying data of the given **ArrayBuffer**.| +|FUNC|napi_is_detached_arraybuffer|Checks whether the given **ArrayBuffer** has been detached.| diff --git a/en/application-dev/tools/how-to-use-arkui-x-sdk.md b/en/application-dev/tools/how-to-use-arkui-x-sdk.md new file mode 100644 index 0000000000000000000000000000000000000000..eed20a3ff0306e53320d9bf9bc35f2fb135d7aff --- /dev/null +++ b/en/application-dev/tools/how-to-use-arkui-x-sdk.md @@ -0,0 +1,39 @@ +# ArkUI-X SDK + +ArkUI-X extends the OpenHarmony ArkUI development framework to different OS platforms like Android and iOS. This way, you can reuse most of the application code (UI and main application logic) based on ArkUI and deploy the code on your OS. + +The ArkUI SDK contains the engine library, plug-in library, and command line tool used to develop ArkUI-X applications. For details about how to obtain the ArkUI-X SDK, see [Acquiring SDK from Mirrors](../../release-notes/ArkUI-X-v1.0.0-canary1.md#acquiring-sdk-from-mirrors). + +## ArkUI-X SDK Components + +The ArkUI-X SDK provides the basic engine library, plug-in library, toolchain, and SDK configuration description files. When DevEco Studio or ACE Tools is used, configure the ArkUI-X SDK based on the following directory structure. + +``` +Path-to-arkui-x-sdk +├── versioncode // Value of apiVersion in the arkui-x.json file in the ArkUI-X SDK root directory. The value is 10. +│ └── arkui-x +│ ├── engine // ArkUI-X SDK engine. +│ │ ├── lib // Dependency of ArkUI-X Android application integration. +│ │ ├── framework // Dependency of ArkUI-X iOS application integration. +│ │ ├── xcframework // Dependency of ArkUI-X iOS application integration. +│ │ ├── ets // New ArkUI-X APIs, for example, @arkui-x.bridge. +│ │ ├── apiConfig.json // Engine library configuration file, which is parsed by IDE and ACE Tools to support on-demand packaging in application build. +│ │ └── systemres // OpenHarmony/HarmonyOS system resources, which support ArkUI-X cross-platform UX consistency. +│ ├── plugins // ArkUI-X SDK plug-ins. +│ │ ├── component // ArkUI component plug-in library and the apiConfig.json file. +│ │ └── api // @ohos API plug-in library and the apiConfig.json file. +│ ├── toolchains // Toolchains, such as ACE Tools. +│ ├── sdkConfig.json // incremental d.ts path and API prefix configuration. +│ ├── arkui-x.json // SDK management configuration, which is automatically generated by the pipeline. +│ └── NOTICE.txt +└── licenses // ArkUI-X SDK agreement to be accepted before the ArkUI-X SDK is downloaded. + ├── ArkUI-X-SDK + └── ArkUI-X-SDK.sha256 +``` + +>**NOTE**
For details about the ArkUI-X SDK directory structure, see [ArkUI-X SDK Directory Structure](../quick-start/sdk-structure-guide.md). + +## ArkUI-X Command Line Tool + +[ACE Tools](../quick-start/start-with-ace-tools.md) is a command line tool provided for ArkUI-X application developers. You can use it to check the development environment check, create a project, build an application, and install, run, and debug your application. + diff --git a/en/application-dev/tutorial/figures/napi-android-demo-result.png b/en/application-dev/tutorial/figures/napi-android-demo-result.png new file mode 100644 index 0000000000000000000000000000000000000000..1f6f161ddc749244e0e25a4e10ca4fcf51baa07c Binary files /dev/null and b/en/application-dev/tutorial/figures/napi-android-demo-result.png differ diff --git a/en/application-dev/tutorial/figures/napi-ios-demo-result.png b/en/application-dev/tutorial/figures/napi-ios-demo-result.png new file mode 100644 index 0000000000000000000000000000000000000000..41c74cafcfcf99b021c0d238260d40fddb768840 Binary files /dev/null and b/en/application-dev/tutorial/figures/napi-ios-demo-result.png differ diff --git a/en/application-dev/tutorial/figures/napi-ios-signing.png b/en/application-dev/tutorial/figures/napi-ios-signing.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3b26b1258a14346d179b3e04c407e515f093ae Binary files /dev/null and b/en/application-dev/tutorial/figures/napi-ios-signing.png differ diff --git a/en/application-dev/tutorial/how-to-explore-native-interface-on-android.md b/en/application-dev/tutorial/how-to-explore-native-interface-on-android.md new file mode 100644 index 0000000000000000000000000000000000000000..6372b92502477fa7a92c9b1a59823870d2d2f433 --- /dev/null +++ b/en/application-dev/tutorial/how-to-explore-native-interface-on-android.md @@ -0,0 +1,425 @@ +# Extending Native APIs on Android + +This tutorial describes how to call Android methods from ArkUI based on the [N-API](../quick-start/ffi-napi-introduction.md) mechanism and plug-in management mechanism on Android. + +## Interface Definition + +Implement the **log** method of the **testplugin** module to call the Android log system and print data from ArkUI. + +| Name| Type| Return Type| Description| +| --- | --- | --- | --- | +| log | string | void | Print data from ArkUI on Android.| + +## How to Develop + +1. Use [ACE Tools](../quick-start/start-overview.md) or IDE to create a Native project. + +``` +// Use ACE Tools to create a Native project. +ace create project +? Please enter the project name: testplugin +? Please enter the bundle name (com.example.testplugin): +? Please enter the system (1: OpenHarmony, 2: HarmonyOS): 1 +? Please enter the template (1: Empty Ability, 2: Native C++): 2 +``` + +2. Import the Native .so file to ArkUI. For example, in the **testplugin\source\entry\src\main\ets\pages\Index.ets** file, **import testplugin from 'libtestplugin.so'** means to use the **libtestplugin.so** capability in ArkUI. Then, provide the ArkUI object named **testplugin** to the application. You can use this object to develop Java plug-ins based on the plug-in management mechanism and finally call the Java **log** method developed in the **testplugin\android\app\src\main\java\com\example\testplugin\TestPlugin.java**. + +```typescript +// Index.ets + +import testplugin from 'libtestplugin.so'; + +testplugin.log("log from ArkUI to Android"); +``` + +3. Implement the **log** method of the **testplugin** module. After that, you can call the **log** method on ArkTS to invoke Android log system and print data from ArkUI. + +## Implementing the Module + +The essence of calling Android Java APIs is to enable ArkTS to call Java APIs. The recommended path for API calling is ArkTS -> C/C++ -> Java. Specifically, implement the Java method on Android, register the Java module using the Java Native Interface (JNI) mechanism, and then register the C/C++ module using the [N-API](../quick-start/ffi-napi-introduction.md#n-api) mechanism for the ArkTS to call. + +### 1. Implementing the Java log Method + +```Java +// android\app\src\main\java\com\example\testplugin\TestPlugin.java + +package com.example.testplugin; + +import android.content.Context; +import android.util.Log; + +public class TestPlugin { + private static final String LOG_TAG = "TestPlugin"; + + // Plugin constructor, which is called by the plugin registration module. + public TestPlugin(Context context) { + // Call the initialization method of the plugin. + nativeInit(); + } + + // Implement the log module. + public void log(String log) { + Log.i(LOG_TAG, log); + } + + // Register the initialization method of the plugin for the plugin constructor to call. + protected native void nativeInit(); +} +``` + +### 2. Invoking the Java log Method Using JNI + +1. Register a Java module on C/C++.
This operation enables C/C++ to call Java because JNI allows interaction between Java code and C/C++ code. + +> **NOTE** +> +> In the Native template of ACE Tools or IDE, files in the SDK **arkui-x\engine\lib\include** directory are stored in the **android\app\src\main\cpp\include** directory. + +```C++ +// android\app\src\main\cpp\test_plugin_jni.cpp + +#include "test_plugin_jni.h" + +#include + +// android\app\src\main\cpp\include\plugin_utils.h defines common APIs for plug-in registration. +#include "plugin_utils.h" + +namespace { + const char TEST_PLUGIN_CLASS_NAME[] = "com/example/testplugin/TestPlugin"; + + static const JNINativeMethod METHODS[] = { + { "nativeInit", "()V", reinterpret_cast(TestPluginJni::NativeInit) }, + }; + + const char METHOD_LOG[] = "log"; + const char SIGNATURE_LOG[] = "(Ljava/lang/String;)V"; + + struct { + jmethodID log; + jobject globalRef; + } g_pluginClass; + +} + +bool TestPluginJni::Register(void* env) +{ + auto* jniEnv = static_cast(env); + jclass cls = jniEnv->FindClass(TEST_PLUGIN_CLASS_NAME); + + // Register the nativeInit function. + bool ret = jniEnv->RegisterNatives(cls, METHODS, sizeof(METHODS) / sizeof(METHODS[0])) == 0; + jniEnv->DeleteLocalRef(cls); + if (!ret) { + return false; + } + return true; +} + +// Called by Java +void TestPluginJni::NativeInit(JNIEnv* env, jobject jobj) +{ + g_pluginClass.globalRef = env->NewGlobalRef(jobj); + jclass cls = env->GetObjectClass(jobj); + + // Obtain the method ID of the log method. + g_pluginClass.log = env->GetMethodID(cls, METHOD_LOG, SIGNATURE_LOG); + env->DeleteLocalRef(cls); +} + +// Called by C++ +void TestPluginJni::Log(std::string log) +{ + auto env = ARKUI_X_Plugin_GetJniEnv(); + jstring jLog = env->NewStringUTF(log.c_str()); + + // Invoke the Java log method using JNI. + env->CallVoidMethod(g_pluginClass.globalRef, g_pluginClass.log, jLog); + + if (jLog != nullptr) { + env->DeleteLocalRef(jLog); + } + + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} +``` + +```C++ +// android\app\src\main\cpp\test_plugin_jni.h + +#ifndef ANDROID_APP_SRC_MAIN_CPP_TEST_PLUGIN_JNI_H +#define ANDROID_APP_SRC_MAIN_CPP_TEST_PLUGIN_JNI_H + +#include +#include +#include + +class TestPluginJni { +public: + TestPluginJni() = delete; + ~TestPluginJni() = delete; + static bool Register(void* env); + // Called by Java + static void NativeInit(JNIEnv* env, jobject jobj); + // Called by C++ + static void Log(std::string log); +}; + +#endif +``` + +Encapsulate the JNI method. + +```C++ +// android\app\src\main\cpp\test_plugin_impl.cpp + +#include "test_plugin_impl.h" + +#include + +#include "plugin_utils.h" +#include "test_plugin_jni.h" + +std::unique_ptr TestPlugin::Create() +{ + return std::make_unique(); +} + +void TestPluginImpl::Log(std::string log) +{ + TestPluginJni::Log(log); +} +``` + +```C++ +// android\app\src\main\cpp\test_plugin_impl.h + +#ifndef ANDROID_APP_SRC_MAIN_CPP_TEST_PLUGIN_IMPL_H +#define ANDROID_APP_SRC_MAIN_CPP_TEST_PLUGIN_IMPL_H + +#include + +#include "test_plugin.h" + +class TestPluginImpl final : public TestPlugin { +public: + TestPluginImpl() = default; + ~TestPluginImpl() override = default; + + void Log(std::string log) override; +}; + +#endif +``` + +### 3. Registering the Java Method and testplugin + +Register the Java method using the plug-in mechanism and register the **testplugin** module using the N-API mechanism to provide the ArkTS log method. + +Implement the C/C++ module corresponding to **testplugin.log**. + +```C++ +// android\app\src\main\cpp\js_test_plugin.cpp + +#include + +#include "napi/native_api.h" +#include "node_api.h" +#include "plugin_utils.h" + +#include "test_plugin.h" + +#ifdef ANDROID_PLATFORM +#include "test_plugin_jni.h" +#endif + +#define NAPI_CALL_BASE(env, theCall, retVal) \ + do { \ + if ((theCall) != napi_ok) { \ + return retVal; \ + } \ + } while (0) + +#define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr) + +static napi_value JSTestPluginLog(napi_env env, napi_callback_info info) +{ + // Create a TestPlugin instance. + auto plugin = TestPlugin::Create(); + if (!plugin) { + return nullptr; + } + + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + char buffer[128]; + size_t buffer_size = 128; + size_t copied; + NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &copied)); + + std::string log; + log = buffer; + + // Call the C++ API. The Log function finally calls TestPluginJni::Log. + plugin->Log(log); + return nullptr; +} +``` + +```C++ +// android\app\src\main\cpp\test_plugin.h + +#ifndef ANDROID_APP_SRC_MAIN_CPP_TEST_PLUGIN_H +#define ANDROID_APP_SRC_MAIN_CPP_TEST_PLUGIN_H + +#include +#include + +class TestPlugin { +public: + TestPlugin() = default; + virtual ~TestPlugin() = default; + + static std::unique_ptr Create(); + + virtual void Log(std::string log) = 0; +}; + +#endif +``` + +Implement the module export entry function. + +```C++ +// android\app\src\main\cpp\js_test_plugin.cpp + +#define DECLARE_NAPI_FUNCTION(name, func) \ + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \ + } + +static napi_value TestPluginExport(napi_env env, napi_value exports) +{ + static napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("log", JSTestPluginLog), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} +``` + +Implement the plug-in JNI registration function. + +```C++ +// android\app\src\main\cpp\js_test_plugin.cpp + +// ANDROID_PLATFORM is a macro specific to Android. +#ifdef ANDROID_PLATFORM +static void TestPluginJniRegister() +{ + const char className[] = "com.example.testplugin.TestPlugin"; + + // ARKUI_X_Plugin_RegisterPlugin provided by the framework registers the plugin JNI environment. + ARKUI_X_Plugin_RegisterJavaPlugin(&TestPluginJni::Register, className); +} +#endif +``` + +Register the module. + +```C++ +// android\app\src\main\cpp\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() +{ + // Register the testPlugin module for ArkTS to call. + napi_module_register(&testPluginModule); +#ifdef ANDROID_PLATFORM + // The JNI plugin registration function runs in the Platform thread. + ARKUI_X_Plugin_RunAsyncTask(&TestPluginJniRegister, ARKUI_X_PLUGIN_PLATFORM_THREAD); +#endif +} +``` + +### Appendix: Compilation Configuration Reference + +#### 1. CMakeLists + +```C++ +// android\app\src\main\cpp\CMakeLists.txt + +cmake_minimum_required(VERSION 3.18.1) + +project("testplugin") + +// Add the ANDROID_PLATFORM macro. +add_definitions(-DANDROID_PLATFORM) + +// Default configuration of the Native template. +set(TESTPLUGIN_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +// Default configuration of the Native template. +include_directories( + ${TESTPLUGIN_ROOT_PATH} + ${TESTPLUGIN_ROOT_PATH}/include +) + +// Build libtestplugin.so. +add_library(testplugin SHARED test_plugin_impl.cpp test_plugin_jni.cpp js_test_plugin.cpp) + +add_library(arkui_android SHARED IMPORTED GLOBAL) +set_target_properties( + arkui_android + PROPERTIES IMPORTED_LOCATION + ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${CMAKE_ANDROID_ARCH_ABI}/libarkui_android.so +) + +target_link_libraries(testplugin PUBLIC arkui_android libc++.a) +``` + +#### 2. build.gradle + +```C++ +// android\app\build.gradle + +android { + defaultConfig { + ...... + + ndk { + abiFilters "arm64-v8a" + } + externalNativeBuild { + cmake { + cppFlags '' + } + } + } + + packagingOptions { + pickFirst 'lib/arm64-v8a/libarkui_android.so' + } + + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.18.1' + } + } +} +``` diff --git a/en/application-dev/tutorial/how-to-explore-native-interface-on-ios.md b/en/application-dev/tutorial/how-to-explore-native-interface-on-ios.md new file mode 100644 index 0000000000000000000000000000000000000000..2488fbebe8267ab9d384ffbe4670b4bb218d5e62 --- /dev/null +++ b/en/application-dev/tutorial/how-to-explore-native-interface-on-ios.md @@ -0,0 +1,252 @@ +# Extending Native APIs on iOS + +This tutorial describes how to call Android methods from ArkUI based on the [N-API](../quick-start/ffi-napi-introduction.md) mechanism and plug-in management mechanism on iOS. + +## Interface Definition + +Implement the **log** method of the **testplugin** module to call the iOS log system and print data from ArkUI. + +| Name| Type| Return Type| Description| +| --- | --- | --- | --- | +| log | string | void | Print data from ArkUI on iOS.| + +## How to Develop + +1. Use ACE Tools(../quick-start/start-overview.md) or IDE to create a Native project. + +``` +// Use ACE Tools to create a Native project. +ace create project +? Please enter the project name: testplugin +? Please enter the bundle name (com.example.testplugin): +? Please enter the system (1: OpenHarmony, 2: HarmonyOS): 1 +? Please enter the template (1: Empty Ability, 2: Native C++): 2 +``` + +2. Import the Native .so file to ArkUI. For example, in the **testplugin\source\entry\src\main\ets\pages\Index.ets** file, **import testplugin from 'libtestplugin.so'** means to use the **libtestplugin.so** capability in ArkUI. Then, provide the ArkUI object named **testplugin** to the application. You can use this object to develop Objective-C (OC) plug-ins based on the plug-in management mechanism and finally call the OC **log** method developed in the **testplugin\ios\app\ios_test_plugin.m**. + +```typescript +// Index.ets + +import testplugin from 'libtestplugin.so'; + +testplugin.log("log from ArkUI to iOS"); +``` + +3. Implement the **log** method of the **testplugin** module. After that, you can call the **log** method on ArkTS to invoke iOS log system and print data from ArkUI. + +## Implementing the Module + +The essence of calling iOS OC APIs is to enable ArkTS to call OC APIs. The recommended path for API calling is ArkTS -> C/C++ -> OC. Specifically, implement the OC API on iOS, encapsulate the OC API in C/C++, and then register the C/C++ module using the [N-API](../quick-start/ffi-napi-introduction.md#n-api) mechanism for the ArkTS to call. + +### 1. Implementing the OC log Method + +```Objective-C +// ios\app\ios_test_plugin.m + +#import "ios_test_plugin.h" + +@implementation iOSTestPlugin + ++ (instancetype)shareinstance{ + static dispatch_once_t onceToken; + static iOSTestPlugin *instance = nil; + dispatch_once(&onceToken, ^{ + instance = [iOSTestPlugin new]; + }); + return instance; +} + +// Implement the log module. +-(void)log: (NSString*) log{ + NSLog(@"%@", log); +} + +@end +``` + +```Objective-C +// ios\app\ios_test_plugin.h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface iOSTestPlugin : NSObject + ++(instancetype)shareinstance; +-(void)log: (NSString*) log; + +@end + +NS_ASSUME_NONNULL_END +``` + +### 2. Implementing the OC log Method Called by C/C++ + +> **NOTE** +> +> In the Native template of ACE Tools or IDE, ensure that the header file in SDK libarkui_ios is referenced. + +```C++ +// ios\app\test_plugin_impl.mm + +#include "test_plugin_impl.h" + +#include + +// plugin_utils.h in libarkui_ios defines common interfaces for plug-in registration. +#include + +#import "ios_test_plugin.h" + +std::unique_ptr TestPlugin::Create() +{ + return std::make_unique(); +} + +void TestPluginImpl::log(std::string log) +{ + NSString* ocLog = [NSString stringWithCString:log.c_str() encoding:NSUTF8StringEncoding]; + [[iOSTestPlugin shareinstance] log: ocLog]; +} +``` + +```C++ +// ios\app\test_plugin_impl.h + +#ifndef IOS_APP_TEST_PLUGIN_IMPL_H +#define IOS_APP_TEST_PLUGIN_IMPL_H + +#include +#include + +#include "test_plugin.h" + +class TestPluginImpl final : public TestPlugin { +public: + TestPluginImpl() = default; + ~TestPluginImpl() override = default; + + void Log(std::string log) override; +}; + +#endif +``` + +### 3. Registering the testplugin Module + +Register the testplugin module using the N-API mechanism to provide the ArkTS log method. + +Implement the C/C++ module corresponding to **testplugin.log**. + +```C++ +// ios\app\js_test_plugin.cpp + +#include + +// The include in libarkui_ios defines the N-APIs. +#include +#include + +#include + +#include "test_plugin.h" + +#define NAPI_CALL_BASE(env, theCall, retVal) \ + do { \ + if ((theCall) != napi_ok) { \ + return retVal; \ + } \ + } while (0) + +#define NAPI_CALL(env, theCall) NAPI_CALL_BASE(env, theCall, nullptr) + +static napi_value JSTestPluginLog(napi_env env, napi_callback_info info) +{ + // Create a TestPlugin instance. + auto plugin = TestPlugin::Create(); + if (!plugin) { + return nullptr; + } + + size_t argc = 1; + napi_value args[1]; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + char buffer[128]; + size_t buffer_size = 128; + size_t copied; + NAPI_CALL(env, napi_get_value_string_utf8(env, args[0], buffer, buffer_size, &copied)); + + std::string log; + log = buffer; + + // Invoke the C++ interface. The Log function finally calls the log method of iOSTestPlugin. + plugin->Log(log); + return nullptr; +} +``` + +```C++ +// ios\app\test_plugin.h + +#ifndef IOS_APP_TEST_PLUGIN_H +#define IOS_APP_TEST_PLUGIN_H + +#include +#include + +class TestPlugin { +public: + TestPlugin() = default; + virtual ~TestPlugin() = default; + + static std::unique_ptr Create(); + + virtual void Log(std::string log) = 0; +}; + +#endif +``` + +Implement the module export entry function. + +```C++ +// ios\app\js_test_plugin.cpp + +#define DECLARE_NAPI_FUNCTION(name, func) \ + { \ + (name), nullptr, (func), nullptr, nullptr, nullptr, napi_default, nullptr \ + } + +static napi_value TestPluginExport(napi_env env, napi_value exports) +{ + static napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("log", JSTestPluginLog), + }; + NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); + return exports; +} +``` + +Register the module. + +```C++ +// ios\app\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() +{ + // Register the testPlugin module for ArkTS to call. + napi_module_register(&testPluginModule); +} +``` diff --git a/en/application-dev/tutorial/how-to-use-napi-on-android.md b/en/application-dev/tutorial/how-to-use-napi-on-android.md new file mode 100644 index 0000000000000000000000000000000000000000..84b7706e2debefe2feccbb32e9c1328088ef9259 --- /dev/null +++ b/en/application-dev/tutorial/how-to-use-napi-on-android.md @@ -0,0 +1,219 @@ +# Using N-APIs on Android + +The N-APIs implement interaction between ArkTS/TS/JS and C/C++ (Native). For details about the N-APIs supported by ArkUI-X and their application scenarios, see [FFI (N-API)](../quick-start/ffi-napi-introduction.md). This tutorial uses the sample Native project in [ArkUI-X/Samples](https://gitee.com/arkui-x/samples) as an example to describe how to use N-APIs to implement cross-language invocation on Android. + +## How to Develop + +The development process is as follows: +1. Set up the environment, that is, obtain the Native project. +2. Implement Native APIs.
Use N-APIs to provide Native capabilities and enable Native APIs to call the methods passed by ArkTS/TS/JS. +3. Declare API definitions.
Add the declaration of the Native APIs exposed to ArkTS. +4. Call Native APIs.
Enable ArkTS/TS/JS to call Native APIs. +5. Build and run the application.
Build the application and run it on Android. + +The following two examples are provided to describe the typical application scenarios of N-APIs by modifying the sample project: +1. Define a Native method named **Add**, which is called by ArkTS with two numbers passed in. The **Add** method adds the two numbers and returns the result to ArkTS. This example describes how to enable ArkTS to call Native methods. +2. Define a Native method named **NativeCallArkTS**, which is called by ArkTS with an ArkTS function passed in. The **NativeCallArkTS** method invokes this ArkTS function and returns the result to ArkTS. This example describes how to enable Native to call ArkTS methods. + +### 1. Setting Up the Environment +Obtain the sample Native project from [ArkUI-X/Samples](https://gitee.com/arkui-x/samples) and use DevEco Studio (V4.0 Beta2 or later) to open the project. The opened project is automatically initialized. + +### 2. Implementing Native APIs + +Develop Native capabilities in N-APIs. In addition, **NativeCallArkTS** in this example demonstrates how Native invokes ArkTS. +```C++ +// entry\src\main\cpp\hello.cpp contains the Native logic. +// Include the N-API header file. +#include "napi/native_api.h" + +// Native method, which has only two input parameters. You do not need to modify them. +// napi_env is the current running context. +// napi_callback_info contains related information, including parameters passed from ArkTS. +static napi_value Add(napi_env env, napi_callback_info info) +{ + // Number of parameters to be obtained from ArkTS. napi_value can be regarded as the representation of the ArkTS value in the N-API method. + size_t argc = 2; + napi_value args[2] = {nullptr}; + + // Obtain the parameters passed from ArkTS in info(). In this example, two ArkTS parameters, arg[0] and arg[1], are obtained. + napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); + + // Obtain the type of arg[0]. + napi_valuetype valuetype0 = napi_undefined; + napi_typeof(env, args[0], &valuetype0); + + // Obtain the type of arg[1]. + napi_valuetype valuetype1 = napi_undefined; + napi_typeof(env, args[1], &valuetype1); + + // Verify the input parameters. If the input parameters are not number, return undefined. + if ((valuetype0 != napi_number) || (valuetype1 != napi_number)) { + napi_value undefined = nullptr; + napi_get_undefined(env, &undefined); + return undefined; + } + + // Convert the obtained ArkTS parameters to the type that can be processed by Native APIs. In this example, the two numbers passed from ArkTS are converted to the double type. + double value0; + napi_get_value_double(env, args[0], &value0); + + double value1; + napi_get_value_double(env, args[1], &value1); + + // Native API service logic, which is adding two numbers in this example. + double nativeSum = value0 + value1; + + // Convert the service logic processing result of the Native API to an ArkTS value and return the value to ArkTS. + napi_value sum = nullptr; + napi_create_double(env, nativeSum , &sum); + return sum; +} + +static napi_value NativeCallArkTS(napi_env env, napi_callback_info info) +{ + // Number of parameters to be obtained from ArkTS. napi_value can be regarded as the representation of the ArkTS value in the Native method. + size_t argc = 1; + napi_value args[1] = {nullptr}; + + // From info(), obtain the parameters passed from ArkTS. In this example, one ArkTS parameter, arg[0], is obtained. + napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); + + // Obtain the type of arg[0]. + napi_valuetype valuetype = napi_undefined; + napi_typeof(env, args[0], &valuetype); + + // Verify the input parameter type. + if (valuetype != napi_function) { + napi_value undefined = nullptr; + napi_get_undefined(env, &undefined); + return undefined; + } + + // Create an ArkTS string as the input parameter of the ArkTS function. + napi_value argv = nullptr; + // Create a JS string. + napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &argv); + + napi_value result = nullptr; + // Invoke the ArkTS function in the Native method, save the return value in result, and return result to ArkTS. + napi_call_function(env, nullptr, args[0], 1, &argv, &result); + + return result; +} + +EXTERN_C_START +// Init() hooks Native methods, such as Add and NativeCallArkTS, in exports. exports is an ArkTS object obtained after you import the Native APIs. +static napi_value Init(napi_env env, napi_value exports) +{ + // Function description struct. The third parameter "Add" is the Native method. + // The first parameter "add" is the name of the ArkTS method. + napi_property_descriptor desc[] = { + { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "nativeCallArkTS", nullptr, NativeCallArkTS, nullptr, nullptr, nullptr, napi_default, nullptr }, + }; + // Hook the Native method to the ArkTS object exports. + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END + +// Information about the module. Record information such as the Init() function and module name. +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 }, +}; + +// When the .so file is opened, the function is automatically called to register the demoModule module. +extern "C" __attribute__((constructor)) void RegisterHelloModule(void) +{ + napi_module_register(&demoModule); +} +``` +### 3. Declaring API Definitions +Declare the Native APIs to be exposed to ArkTS in the d.ts file. +```js +// entry\src\main\cpp\types\libentry\index.d.ts contains the declaration of the Native APIs exposed to ArkTS. +// Declare the Native APIs to be exposed to ArkTS. +export const add: (a: number, b: number) => number; +export const nativeCallArkTS: (a: object) => string; +``` + +### 4. Calling Native APIs +Call Native APIs on ArkTS/TS/JS. +1. The **entry.add** API implements the ArkTS -> Native invocation. +2. The **entry.nativeCallArkTS** API implements ArkTS -> Native -> ArkTS invocation. +```js +// entry\src\main\ets\pages\Index.ets contains the ArkTS logic. +// Import the Native APIs. +import entry from 'libentry.so' + +function TestFunction(str) { + let ret = str + ' world!' + return ret; +} + +@Entry +@Component +struct Index { + @State message: string = 'Test native api: 2 + 3 = ?' + @State message2: string = 'Click me' + + build() { + Row() { + Column() { + // The first button calls the add() method, which uses the Native Add() method to add the two numbers. + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + .onClick(() => { + this.message = "Test native api: 2 + 3 = " + entry.add(2, 3); + console.log("Test NAPI 2 + 3 = " + entry.add(2, 3)); + }) + // The second button calls the nativeCallArkTS() method, which uses the Native NativeCallArkTS method to execute the ArkTS function. + Text(this.message2) + .fontSize(50) + .fontWeight(FontWeight.Bold) + .onClick(() => { + this.message2 = entry.nativeCallArkTS(TestFunction); + }) + } + .width('100%') + } + .height('100%') + } +} +``` + +### 5. Building and Running the Application +On DevEco Studio (V4.0 Beta2 or later), choose **Build** > **Build Hap(s)/APP(s)** > **Build APP(s)** to build the application. Use Android Studio to open the **.arkui-x\android** folder of the Native project and click **Run app** to run the application. After the application runs, click the texts on the page. +![Running Effect](./figures/napi-android-demo-result.png) + +## Development Guidelines + +### Registration + +* To prevent conflicts with symbols in the .so file, add "static" to the function (such as the Init() function) corresponding to **nm_register_func**. +* The entry of module registration, that is, the function name modified by **\_\_attribute\_\_((constructor))** (for example, the **RegisterHelloModule** function), must be unique. + +### .so Naming Rules + +The .so file names must comply with the following rules: + +* Each module has a .so file. +* For example, if the module name is **entry**, the name of the .so file is **libentry.so**. The **nm_modname** field in **napi_module** must be **entry**. The case of the **nm_modname** field must be the same as that of the module name. When importing the module, use **import entry from 'libentry.so'**. + +### Constraints on JS Object Threads + +The ArkCompiler protects JS object threads. Improper use may cause an application crash. Observe the following rules: + +* The N-APIs can be used only by JS threads. +* The Native API input parameter **env** is bound to the thread and cannot be used across threads. The JS object created by a Native API can be used only in the thread, in which the object is created, that is, the JS object is bound to the **env** of the thread. + +### Header File Import + +Import **napi/native_api.h**. Otherwise, an error indicating that the N-API cannot be found will be reported. diff --git a/en/application-dev/tutorial/how-to-use-napi-on-ios.md b/en/application-dev/tutorial/how-to-use-napi-on-ios.md new file mode 100644 index 0000000000000000000000000000000000000000..48a256fe33464482b70e0dae202eac5dc1f6983e --- /dev/null +++ b/en/application-dev/tutorial/how-to-use-napi-on-ios.md @@ -0,0 +1,15 @@ +# Using N-APIs on iOS + +The N-APIs implement interaction between ArkTS/TS/JS and C/C++ (Native). For details about the N-APIs supported by ArkUI-X and their application scenarios, see [FFI (N-API)](../quick-start/ffi-napi-introduction.md). The use of N-APIs on iOS is the same as that on Android except the build and running of applications. This tutorial elaborates how to build and run an application using N-APIs on iOS platform. For details about other steps, see [Using N-APIs on Android](./how-to-use-napi-on-android.md). + +### Building and Running the Application +Different from the application build and running on Android, the Native projects built and run on iOS must be signed. The procedure is as follows: +1. On DevEco Studio (V4.0 Beta2 or later), choose **Build** > **Build Hap(s)/APP(s)** > **Build APP(s)** to build an application. + +2. Use the Xcode tool to open the **.arkui-x\ios** file and sign the file using Xcode. + + ![signing](./figures/napi-ios-signing.png) + +3. Click the **Run** button in Xcode to run the application. + +![Result](./figures/napi-ios-demo-result.png)