For AI agents: the complete documentation index is available at /next/zh/llms.txt, the full documentation bundle is available at /next/zh/llms-full.txt, and this page is available as Markdown at /next/zh/guide/autolink.md.
Lynx
  • 简体中文
  • 原生库与 Autolink

    Lynx 原生库是一个 npm 包,可以打包元件、原生模块和 Service 中的任意组合,供宿主 Lynx 应用消费。在此之前,这些能力只能在每个宿主应用里各接一次,Android、iOS 和 HarmonyOS 还要分别写一遍。Autolink 是配套的集成机制,让宿主应用自动发现 node_modules 中安装的库,并接入它们的原生能力,避免为每个元件、原生模块或 Service 手动写注册代码。

    Autolink 在 Android 和 iOS 上提供应用级全局注册。HarmonyOS 接入方式已在下文说明,但尚未包含在正式发布的 Lynx SDK 中。Autolink 也覆盖 Lynxtron 原生库使用的包元数据和宿主加载,但不会生成单个 LynxView 的局部 Library 注册或 Web 接入代码。

    本页分为两部分:要在应用里用上一个已有的库,从使用库开始;要把自己的原生能力发布成库,从开发库开始。想先建立整体印象,可以直接看 Autolink 工作原理

    开始前的准备
    工具可用性

    请使用与应用 Lynx SDK 同一发布渠道的 Autolink 工具。相关 package 和 plugin 名称如下:

    • npm:create-lynx-library@lynx-js/autolink-codegenlynx-autolink-codegen binary)
    • Android:Gradle plugin org.lynxsdk.lynx.library-settingsorg.lynxsdk.lynx.library-build
    • iOS:Ruby gem cocoapods-lynx-library
    • HarmonyOS:Hvigor plugin @lynx/lynx-library-plugin
    • Lynxtron:create-lynx-library 可以生成 shared native library 包,@lynx-js/lynxtron-dev-plugins 通过 pluginLynxtron() 提供宿主侧加载能力。

    如果当前配置的 registry 还无法解析其中某个包,说明你使用的 Lynx SDK 发布版本尚未在该 registry 中包含 Native Autolink。此时请继续使用既有手动原生注册方式,等待匹配版本发布后再接入。

    平台兼容性

    下表展示 Lynx Compatibility Data 已收录平台的 Autolink 支持情况。Lynxtron 的宿主侧接入方式记录在接入 Autolink 中,但 Lynxtron 不在此表的覆盖范围内。

    什么是 Lynx 原生库

    一个库就是一个 npm 包,可以包含以下能力的任意组合:

    • 元件:Lynx 渲染的自定义原生元件,例如 <x-button>
    • 原生模块:可以在 Lynx 应用代码中调用的、带类型声明的 JavaScript-to-native API。
    • Service:应用级的原生单例,可以被库内的其他能力依赖。

    每个库都通过包根目录下的 lynx.lib.json 清单文件声明原生入口。这三类能力相互独立:一个库可以只暴露元件、只暴露原生模块、只暴露 Service,也可以暴露它们的任意组合。

    应用侧像安装普通 npm 依赖一样安装库。Android Gradle 插件、iOS CocoaPods 插件和 HarmonyOS Hvigor 插件会读取 lynx.lib.json,把原生代码链接进宿主应用;宿主应用本身无需了解每个库具体暴露了哪些能力。Lynxtron 会从已安装包中读取同一份清单,把匹配到的包文件收集到宿主输出目录,并在宿主 bundle 前置生成代码,加载每个已收集包的 ./lynxtron 入口。

    使用库

    本节面向把一个或多个库集成进宿主 Lynx 应用的应用团队。

    宿主应用项目结构

    接入 Autolink 前,需要先确保宿主应用有一个可以安装 npm 包的项目根目录,并暴露原生应用的构建入口。典型结构如下:

    lynx-app/
    ├── package.json
    ├── android/
    │   ├── settings.gradle
    │   └── app/
    │       └── build.gradle
    ├── ios/
    │   └── Podfile
    ├── harmony/
    │   ├── hvigorconfig.ts
    │   └── entry/
    │       └── hvigorfile.ts
    ├── shared/
    │   ├── CMakeLists.txt
    │   └── ...
    ├── dist/
    └── src/
    • package.json 是必需的,用来声明 Autolink 库依赖。
    • Android 接入需要 Gradle settings 文件,例如 settings.gradlesettings.gradle.kts,以及 Android application 的构建文件,例如 app/build.gradleapp/build.gradle.kts
    • iOS 接入需要 CocoaPods 入口,通常是 Podfile。如果团队通过 Bundler 管理 Ruby 依赖,可以在 Gemfile 中维护 cocoapods-lynx-library gem。
    • HarmonyOS 接入需要根目录的 hvigorconfig.ts,以及一个依赖 @lynx/lynx 的 entry 或 feature HAP 模块。
    • shared/ 用于宿主应用自有的跨端原生源码和 CMake 构建入口,需要自行编译。
    • Lynxtron 接入需要应用具备宿主侧 Rspack 构建,并通过 pluginLynxtron() 安装和加载原生库;一般消费编译后的 dist/ 产物。

    安装依赖后,Autolink 会从已安装 npm 包的包根目录扫描 lynx.lib.jsonpackage-lock.jsonpnpm-lock.yamlyarn.lock 等 lockfile 有助于可复现安装,但不是 Autolink 的必需项。

    宿主应用只需要接入一次 Autolink。接入完成后,已安装的库会从 node_modules 中被发现,并在 Lynx 初始化时通过生成的 registry 自动注册。

    settings.gradle 中启用 settings plugin,让库的 Android 工程可以通过 lynx.lib.json 被发现并 include 进来:

    plugins {
      id 'org.lynxsdk.lynx.library-settings' version '4.0.1'
    }

    在 Android application 工程中启用 build plugin,让生成的 registry 加入应用源码,并自动把库工程接入为依赖:

    plugins {
      id 'com.android.application'
      id 'org.lynxsdk.lynx.library-build' version '4.0.1'
    }

    Gradle sync/build 后,Autolink 会生成固定的 Android registry 入口并加入应用源码。应用初始化 LynxEnv 时会自动加载该入口,库提供的元件、原生模块和 Service 会按应用全局注册生效;业务侧无需额外编写原生初始化代码。

    在 iOS 构建环境中安装 cocoapods-lynx-library gem。然后在应用的 Podfile 中加入 CocoaPods plugin,并调用 use_lynx_library!。执行 pod install 时,插件会加入库的 podspec 和生成的 registry pod:

    plugin 'cocoapods-lynx-library'
    
    target 'LynxApp' do
      use_lynx_library!
    end

    执行 pod install 后,Autolink 会生成 registry pod,并把它接入 Lynx 的初始化流程。应用创建 LynxConfig 或初始化 LynxEnv 时,库提供的元件、原生模块和 Service 会自动注册生效;业务侧无需导入生成文件或编写额外初始化代码。

    在 HarmonyOS 工程根目录的 hvigor/hvigor-config.json5 中添加插件依赖:

    {
      modelVersion: '5.0.0',
      dependencies: {
        '@lynx/lynx-library-plugin': '^0.1.0',
      },
    }

    在 HarmonyOS 工程根目录创建 hvigorconfig.ts,并启用一次插件:

    import * as hvigorApi from '@ohos/hvigor';
    import { enableHarmonyLynxAutolink } from '@lynx/lynx-library-plugin';
    
    enableHarmonyLynxAutolink(hvigorApi, {
      moduleName: 'entry',
    });

    当工程中只有一个依赖 @lynx/lynx 的 entry 或 feature HAP 时,可以省略 moduleName。如果有多个 Lynx HAP 模块,则必须显式指定目标模块。

    在 Hvigor 创建模块节点之前,插件会扫描可见的 node_modules,通过 Hvigor 公开的 parseJsonFile() API 解析 HarmonyOS JSON5 元数据,在工程忽略的 .hvigor/lynx-autolink/<moduleName> 缓存目录生成 Registry HAR,并通过 hvigorConfig.includeNode() 把 Library HAR 和 Registry HAR 加入构建图。目标 HAP 完成求值后,插件通过 HAP model API 注入 Registry 依赖和生成的资源目录,并设置 module.appStartup。AppStartup 源码位于 HAP 模块的 build/generated/lynx-autolink 目录;生成的 Hvigor task 会在 clean 后、当前 target 的 PreBuild 前恢复这些文件。插件不会修改应用的 src 目录,也不会改写版本库中的 build-profile.json5

    生成的 AppStartup task 会在应用代码创建 Lynx runtime 之前于主线程运行,并且只调用 Registry HAR 中幂等的 setupGlobal()。如果 HAP 已配置 AppStartup profile,插件会保留原有 task 和 configEntry,并追加 Lynx task。应用无需运行 lynx-harmony-autolink 命令,也无需手动调用 setupGlobal()

    Lynxtron 为桌面端原生库提供了 Autolink 支持。并不是所有嵌入 Lynx 的桌面宿主都开箱支持 Autolink,这是 Lynxtron 自带的能力。

    在 Lynxtron 宿主侧 Rspack 配置中使用 pluginLynxtron()。这个插件默认包含 Lynxtron Autolink:它会扫描已安装依赖中的 lynx.lib.json,把匹配到的原生库包收集到宿主输出目录,并注入前置代码来加载每个已收集包的 ./lynxtron 入口。对于声明了 platforms.lynxtron.path 的包,业务代码直接导入 <package>/lynxtron 时,也会被别名到生成的代理模块,并在运行时解析已收集的包。./lynxtron 入口负责加载当前宿主对应的 .node 产物。

    import { pluginLynxtron } from '@lynx-js/lynxtron-dev-plugins/rspack';
    
    export default {
      target: 'electron-main',
      plugins: [
        pluginLynxtron({
          isDev: process.env.NODE_ENV === 'development',
          entry: './dist/desktop',
        }),
      ],
    };

    entry 是 Lynxtron 宿主自身的 bundle 入口,pluginLynxtron() 会以它为基准放置已收集的原生库包。完整的参数含义请参考 @lynx-js/lynxtron-dev-plugins 包。

    Lynxtron 加载原生库后,其中的 Lynx 静态注册会在 Lynx runtime 中生效。库作者不需要 Lynxtron 专用注册宏。

    安装库

    应用接入 Autolink 后,在 Lynx 应用中安装库:

    npm install @example/lynx-button

    每个库包都会在包根目录暴露 lynx.lib.json 清单文件。Autolink 会扫描已安装 npm 包中的这个文件。

    {
      "platforms": {
        "android": {
          "packageName": "com.example.button",
          "sourceDir": "android"
        },
        "ios": {
          "sourceDir": "ios",
          "podspecPath": "ios/build.podspec"
        },
        "harmony": {
          "packageDir": "harmony"
        },
        "lynxtron": {
          "path": "dist"
        },
        "macos": {
          "sourceDir": "shared"
        },
        "windows": {
          "sourceDir": "shared"
        }
      }
    }

    Android 侧必须声明 platforms.android.packageNamesourceDir 默认是 android。iOS 侧 sourceDir 默认是 iospodspecPath 默认使用 iOS 源码目录下找到的第一个 .podspec 文件。HarmonyOS 侧 packageDir 默认是 harmony;该目录必须是完整的源码 HAR,包含 hvigorfile.tsoh-package.json5build-profile.json5src/main/module.json5,以及由 main 声明的 package 入口或 Index.ets

    platforms.macos.sourceDirplatforms.windows.sourceDir 指向以源码形式暴露的 shared/ 目录。它是跨端原生源码结构,后续也可以被更多平台复用。

    对于 Lynxtron,platforms.lynxtron.path 声明原生产物根目录,通常是 distpluginLynxtron() 会收集匹配到的包文件并校验产物;包的 ./lynxtron export 负责加载当前宿主的 .node,例如 dist/macos/arm64/lynx-button.nodedist/windows/x64/lynx-button.node

    安装或更新库后,Android 或 HarmonyOS 侧重新构建应用,iOS 侧重新执行 pod install,让生成的 registry 和原生依赖刷新。应用中不需要为每个库再写手动注册代码。

    开发库

    本节面向开发可复用原生库供其他 Lynx 应用安装的库作者。

    库包结构

    一个典型的库结构如下;shared/ 用于跨端原生实现,如果同一个包也发布 Lynxtron 原生产物,同一个结构中也可以包含 Lynxtron 加载入口和按宿主区分的输出:

    lynx-button/
    ├── package.json
    ├── lynx.lib.json
    ├── types/
    │   ├── index.d.ts
    │   ├── platform-native-module.d.ts
    │   └── napi-native-module.d.ts
    ├── src/
    │   └── index.ts
    ├── generated/
    │   ├── ButtonModule.ts
    │   └── ButtonModuleNapi.ts
    ├── android/
    │   └── src/main/java/com/example/button/
    │       ├── ButtonElement.java
    │       ├── ButtonModule.java
    │       ├── ButtonService.java
    │       └── generated/ButtonModuleSpec.java
    ├── ios/
    │   ├── build.podspec
    │   └── src/
    │       ├── ButtonElement.m
    │       ├── ButtonModule.m
    │       ├── ButtonService.m
    │       └── generated/
    │           ├── ButtonModuleSpec.h
    │           └── ButtonModuleSpec.m
    ├── harmony/
    │   ├── Index.ets
    │   ├── hvigorfile.ts
    │   ├── oh-package.json5
    │   ├── build-profile.json5
    │   └── src/main/
    │       ├── module.json5
    │       └── ets/
    │           ├── LynxLibraryProviderImpl.ets
    │           ├── ButtonElement.ets
    │           ├── ButtonModule.ets
    │           ├── ButtonService.ets
    │           └── generated/ButtonModuleSpec.ets
    ├── shared/
    │   ├── CMakeLists.txt
    │   ├── nativeModule/
    │   └── elements/
    ├── lynxtron/
    │   ├── CMakeLists.txt
    │   ├── index.cjs
    │   └── library_entry.cc
    ├── dist/
    │   ├── macos/
    │   │   └── arm64/
    │   │       └── lynx-button.node
    │   └── windows/
    │       └── x64/
    │           └── lynx-button.node
    └── example/
    • package.json 让库可以通过 npm 安装,并通常提供 codegen 脚本。
    • lynx.lib.json 是 Autolink 清单文件,用来告诉宿主应用各平台的原生 package 或产物根目录在哪里。
    • types/index.d.ts 汇总导出原生模块类型声明;选中对应能力时,平台 Native Module 声明位于 types/platform-native-module.d.ts,N-API Native Module 声明位于 types/napi-native-module.d.ts
    • src/index.ts 导出应用代码需要 import 的 JavaScript API。
    • android/ios/harmony/ 放置原生实现以及生成的原生 spec。HarmonyOS 目录是一个完整的源码 HAR,包含模块级的 hvigorfile.ts
    • shared/ 放置跨端原生代码,例如跨端自渲染元件实现,以及 shared/nativeModule/ 下的 C++ N-API 回调桩代码。
    • lynxtron/dist/ 放置 Lynxtron 加载入口和按宿主区分的输出。
    • example/ 是库作者用于本地验证的示例应用。

    创建库

    使用交互式命令创建库:

    npm create lynx-library

    在脚本或测试中,也可以用 flags 直接生成:

    npm create lynx-library -- \
      --dir ./lynx-button \
      --features native-module,napi-native-module,element,service \
      --platforms android,ios,harmony,lynxtron \
      --package-name @example/lynx-button \
      --android-package com.example.button \
      --module-name ButtonModule \
      --element-name x-button \
      --service-name ButtonService

    生成的库会包含:

    • 带有 "codegen": "lynx-autolink-codegen"package.json
    • 用于 Android、iOS、HarmonyOS 和 Lynxtron Autolink 元数据的 lynx.lib.json
    • types/index.d.tstypes/platform-native-module.d.tstypes/napi-native-module.d.ts,根据选择的模块能力生成对应类型声明
    • JavaScript facade 入口 src/index.ts
    • 原生源码目录 android/ios/,以及完整的 harmony/ 源码 HAR
    • 生成跨端实现时使用的 shared/ native source
    • 生成 Lynxtron 产物时使用的 lynxtron/ 加载入口
    • example/tsconfig.jsonREADME.md

    在库根目录运行 codegen:

    npm run codegen

    lynx-autolink-codegen 会读取 lynx.lib.json。对于原生模块,它会扫描 types/ 下的 Native Module 声明文件,查找带有 @lynxmodule 的声明:

    /** @lynxmodule */
    export declare class ButtonModule {
      getLabel(id: string): string;
      setEnabled(id: string, enabled: boolean): void;
    }

    它会生成:

    • JavaScript facade:generated/<ModuleName>.ts
    • Android platform native module:<ModuleName>Spec.java
    • iOS platform native module:<ModuleName>Spec.h<ModuleName>Spec.m
    • HarmonyOS platform native module:<packageDir>/src/main/ets/generated 下的 <ModuleName>Spec.ets
    • N-API 原生模块:shared/nativeModule/ 下的 C++ N-API 回调桩代码

    HarmonyOS spec 当前支持 voidstringnumberboolean 和带 null 的 nullable union。其他生成目标保留已有的数组、对象/maps/sets、promise,以及 ArrayBuffer、typed arrays、BigIntDateFunctionSymbolBufferValue 等 N-API wrapped value types 支持。

    编写 Native API

    在原生源码中使用平台对应的 Lynx 注解或注册方式,Autolink 就能发现库提供的能力。Android 和 iOS 原生模块通常继承 lynx-autolink-codegen 生成的 spec;元件和 Service 会通过原生标记被发现。HarmonyOS Library 则导出一个统一注册所有能力的 Provider。

    原生模块示例:

    package com.example.button;
    
    import com.example.button.generated.ButtonModuleSpec;
    import com.lynx.jsbridge.LynxNativeModule;
    import com.lynx.jsbridge.LynxMethod;
    import com.lynx.tasm.behavior.LynxContext;
    import java.util.HashMap;
    import java.util.Map;
    
    @LynxNativeModule(name = "ButtonModule")
    public final class ButtonModule extends ButtonModuleSpec {
      private final Map<String, Boolean> enabledState = new HashMap<>();
    
      public ButtonModule(LynxContext context) {
        super(context);
      }
    
      @Override
      @LynxMethod
      public String getLabel(String id) {
        return "Button " + id;
      }
    
      @Override
      @LynxMethod
      public void setEnabled(String id, boolean enabled) {
        enabledState.put(id, enabled);
      }
    }

    元件示例:

    package com.example.button;
    
    import android.content.Context;
    import android.view.Gravity;
    import android.widget.TextView;
    import com.lynx.tasm.behavior.LynxElement;
    import com.lynx.tasm.behavior.LynxContext;
    import com.lynx.tasm.behavior.LynxProp;
    import com.lynx.tasm.behavior.ui.LynxUI;
    
    @LynxElement(name = "x-button")
    public final class ButtonElement extends LynxUI<TextView> {
      public ButtonElement(LynxContext context) {
        super(context);
      }
    
      @Override
      protected TextView createView(Context context) {
        TextView view = new TextView(context);
        view.setGravity(Gravity.CENTER);
        view.setText("x-button");
        return view;
      }
    
      @LynxProp(name = "text")
      public void setText(String text) {
        mView.setText(text == null ? "" : text);
      }
    }

    Service 示例:

    package com.example.button;
    
    import android.content.Context;
    import com.lynx.tasm.service.IServiceProvider;
    import com.lynx.tasm.service.LynxService;
    
    @LynxService
    public final class ButtonService implements IServiceProvider {
      private Context appContext;
    
      @Override
      public Class<? extends IServiceProvider> getServiceClass() {
        return ButtonService.class;
      }
    
      @Override
      public void onInitialize(Context context) {
        appContext = context.getApplicationContext();
      }
    
      public void recordClick(String id) {
        // Send analytics or call platform capabilities here.
      }
    }

    原生模块示例:

    // ButtonModule.h
    #import <Foundation/Foundation.h>
    #import <Lynx/LynxModule.h>
    #import "generated/ButtonModuleSpec.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @LynxNativeModule("ButtonModule")
    @interface ButtonModule : NSObject <ButtonModuleSpec>
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    // ButtonModule.m
    #import "ButtonModule.h"
    
    @implementation ButtonModule {
      NSMutableDictionary<NSString *, NSNumber *> *_enabledState;
    }
    
    - (instancetype)init {
      self = [super init];
      if (self) {
        _enabledState = [NSMutableDictionary dictionary];
      }
      return self;
    }
    
    - (NSString *)getLabel:(NSString *)buttonId {
      return [NSString stringWithFormat:@"Button %@", buttonId];
    }
    
    - (void)setEnabled:(NSString *)buttonId enabled:(BOOL)enabled {
      _enabledState[buttonId] = @(enabled);
    }
    
    @end

    元件示例:

    // ButtonElement.h
    #import <UIKit/UIKit.h>
    #import <Lynx/LynxUI.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface ButtonElement : LynxUI<UILabel *>
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    // ButtonElement.m
    #import "ButtonElement.h"
    #import <Lynx/LynxPropsProcessor.h>
    
    @LynxElement("x-button")
    @implementation ButtonElement
    
    LYNX_PROP_SETTER("text", setText, NSString *) {
      self.view.text = value ?: @"";
    }
    
    - (UILabel *)createView {
      UILabel *label = [[UILabel alloc] init];
      label.textAlignment = NSTextAlignmentCenter;
      label.text = @"x-button";
      return label;
    }
    
    @end

    Service 示例:

    // ButtonService.h
    #import <Foundation/Foundation.h>
    #import <LynxServiceAPI/ServiceAPI.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @protocol ButtonServiceProtocol <LynxServiceProtocol>
    
    - (void)recordClick:(NSString *)buttonId;
    
    @end
    
    @interface ButtonService : NSObject <ButtonServiceProtocol>
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    // ButtonService.m
    #import "ButtonService.h"
    
    @LynxService(ButtonService, ButtonServiceProtocol)
    @implementation ButtonService
    
    + (instancetype)sharedInstance {
      static ButtonService *service;
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        service = [[ButtonService alloc] init];
      });
      return service;
    }
    
    - (void)recordClick:(NSString *)buttonId {
      // Send analytics or call platform capabilities here.
    }
    
    @end

    在 iOS 侧,Autolink 会扫描库源码中的 @LynxNativeModule(...)@LynxElement(...)@LynxService(...) 声明,并把发现的能力加入生成的 registry。旧版 iOS Service API 仍提供 @LynxServiceRegister(...) 以兼容已有代码。新库代码推荐使用 @LynxService(...)

    HarmonyOS Library 通过一个 Provider 注册全部能力。Index.ets 必须导出名为 LynxLibraryProviderImpl 的 class:

    // harmony/Index.ets
    export { LynxLibraryProviderImpl } from './src/main/ets/LynxLibraryProviderImpl';
    export { ButtonElement } from './src/main/ets/ButtonElement';
    export { ButtonModule } from './src/main/ets/ButtonModule';
    export { ButtonService } from './src/main/ets/ButtonService';

    Native Module 继承生成的 ArkTS spec:

    import { ButtonModuleSpec } from './generated/ButtonModuleSpec';
    
    export class ButtonModule extends ButtonModuleSpec {
      getLabel(id: string): string {
        return `Button ${id}`;
      }
    
      setEnabled(_id: string, _enabled: boolean): void {}
    }

    Element 使用 HarmonyOS 现有的 UIBase API:

    import { UIBase } from '@lynx/lynx';
    
    export class ButtonElement extends UIBase {
      layout(
        _x: number,
        _y: number,
        _width: number,
        _height: number,
        _paddingLeft: number,
        _paddingTop: number,
        _paddingRight: number,
        _paddingBottom: number,
        _marginLeft: number,
        _marginTop: number,
        _marginRight: number,
        _marginBottom: number,
        _sticky?: number[],
      ): void {}
    }

    Service 使用 Lynx 现有的 Service 接口。下面的示例提供全局 Extension Service:

    import { ILynxExtensionService, LynxContext } from '@lynx/lynx';
    
    export class ButtonService implements ILynxExtensionService {
      static readonly instance: ButtonService = new ButtonService();
    
      onLynxViewSetup(
        _context: LynxContext,
        _uiDelegate: number[],
        _isHostRenderer: boolean,
      ): void {}
    
      onLynxViewDestroy(_context: LynxContext): void {}
    }

    Provider 把这些实现接入 Lynx:

    import {
      Behavior,
      LynxLibraryProvider,
      LynxLibraryRegistry,
      LynxServiceType,
    } from '@lynx/lynx';
    import { ButtonElement } from './ButtonElement';
    import { ButtonModule } from './ButtonModule';
    import { ButtonService } from './ButtonService';
    
    export class LynxLibraryProviderImpl implements LynxLibraryProvider {
      register(registry: LynxLibraryRegistry): void {
        registry.registerBehavior('x-button', new Behavior(ButtonElement));
        registry.registerModule('ButtonModule', { moduleClass: ButtonModule });
        registry.registerService(LynxServiceType.Extension, ButtonService.instance);
      }
    }

    如果 package 需要执行原生 XElement 注册等初始化逻辑,可以使用 registerInitializer(() => packageInit())。原生 XElement 继续使用现有的 C++ 注册链路,不要为了接入 Autolink 而将它包装成 UIBase 实现。

    Registry 会拒绝重复的全局 Element tag、Native Module name 和 Service type,并在错误信息中标明 package。全局 Native Module 会先于 LynxViewLynxBackgroundRuntime 显式传入的 module map 安装,因此已有的局部 module 仍然可以覆盖同名全局 module。

    Lynxtron 原生库使用共享的 Lynx C/C++ 扩展 API 和静态注册宏。本页只说明 Autolink 如何发现和加载包;原生模块的实现请看 Desktops (Node-API) 标签页,自定义元件的实现请看 Desktops 标签页:

    发布库

    像发布普通 npm 包一样发布库:选一个包名,通常是带 scope 的 @example/lynx-button,在 package.json 中设置版本号,然后执行 npm publish。应用团队把发布版本写入自己的 package.json,下次安装依赖时 Autolink 会自动识别。建议在库的 peerDependencies 中固定兼容的 Lynx SDK 版本范围,这样当库和宿主 SDK 出现版本错配时,应用团队能够第一时间收到清晰提示。

    Autolink 在构建期运行。它会扫描 node_modules 中每个 npm 包的 lynx.lib.json 清单,然后为当前平台生成或提供宿主接入数据。各平台的生成方式如下:

    • Android:由 Gradle settings 插件和 build 插件配合完成 registry 生成。
    • iOS:由 CocoaPods 插件完成,并产出 registry pod。
    • HarmonyOS:在 Hvigor 配置阶段生成源码 Registry HAR 和 AppStartup task。
    • Lynxtron:运行在宿主侧 Rspack 构建中,收集匹配到的原生包,把加载代码注入宿主 bundle,并让已加载库里的 Lynx 静态注册提供对应的原生模块和元件。

    Android、iOS 和 HarmonyOS 都只会在初始化阶段加载一次生成的 registry,因此宿主代码中不需要任何逐库的接入逻辑。

    除非另有说明,本项目采用知识共享署名 4.0 国际许可协议进行许可,代码示例采用 Apache License 2.0 许可协议进行许可。