iOS 动态化(js)

大约 4 分钟

iOS 动态化(js)

在iOS端,要实现动态下发,推荐使用js产物的模式来实现。Kuikly支持直接将core + 业务代码编译成js产物,动态下发执行。

使用该模式的优势:

  1. 省安装包,native仅需要继承kuiklyiOSRender部分
  2. 支持动态下发,支持更快的业务迭代速度
  3. 支持hotReload,每次修改kotlin代码,仅需要从新生成js产物,而无需从新编译宿主app

下面举例说明在iOS上使用js产物进行下发:

js 产物构建

Kuikly中的js打包支持两种模式

  1. 将所有的业务代码打包成一个js,这种打包方式适用于开发阶段或者将重要的页面内置到安装包的场景
  2. 每个Page打包成一个js,这种打包方式适用在运行在线上的生产环境

Kuiklyjs打包的gradle任务如下:

  1. packLocalJSBundleXX: 将所有的业务代码编译成一份js文件
  2. packSplitJSBundleXX: 将每个Page编译成一个js文件

若无任务,检查build.gradle是否有配置:

1、配置 Kuikly 插件的 JS 产物设置,包括输出文件名、分包构建页面列表以及可选的 Hermes 编译支持。

kuikly {
  // JS 产物配置
  js {
      // 构建产物名,与 KMM 插件 webpackTask#outputFileName 一致
      outputName("nativevue2")
      // 可选:分包构建时的页面列表,如果为空则构建全部页面
      // addSplitPage("route","home")

      // 可选:若使用Hermes引擎,可开启Hermes编译,输出HBC文件
      // enableHermesCompile = true
  }
}

2、配置 Kotlin Multiplatform 项目的 Kotlin/JS 编译选项,设置模块名称、输出文件名、Webpack 配置以及生成可直接运行的 JavaScript 文件。

kotlin {
  js(IR) {    // 设置Kotlin/JS 的编译模式为 IR(Intermediate Representation)
     moduleName = "nativevue2"
       browser {
          webpackTask {
              outputFileName = "${moduleName}.js" // 最后输出的名字
          }
          commonWebpackConfig {
              output?.library = null // 不导出全局对象,只导出必要的入口函数
          }
      }
      binaries.executable() //将kotlin.js与kotlin代码打包成一份可直接运行的js文件
  }
}

注:如果没有看到脚本则需到Preferences里去掉以下选项

img
img

packLocalJSBundleXX产物

packLocalJSBundleXX构建出的产物位于

localJS
localJS

nativevue2.zip为最终的产物, 将它解压你可以

nativevue2.js   // js文件
config.json     // nativevue2.js文件里打包的page列表
assets          // 资源目录

packSplitJSBundleXX

packSplitJSBundleXX构建出的产物位于

spiltJS
spiltJS

nativevue2.zip为最终的产物, 将它解压后,能看到每个page对应一个js bundle

提示

Kuikly联动Shiply开发了「多轮次灰度」、「增量/差量包」、「质量联动监控、告警和止损」等发布能力,如您有动态化发布需求,强烈建议接入Shiplyopen in new window

js 产物加载

HotReload热重载方式运行

1、配置并启动Node环境

# 配置Node环境依赖
npm install
# 启动Node环境
npm run server

2、运行

参照js模式运行

加载本地js产物运行动态化模式

1、修改KuiklyRenderViewController的initWithPageName增加本地js加载时的标志位

@implementation KuiklyRenderViewController {
    // ...
    BOOL _useJS;	// 增加js模式启动的标志位
}

- (instancetype)initWithPageName:(NSString *)pageName pageData:(NSDictionary *)pageData hotReloadIp:(NSString * _Nullable)ip {
    if (self = [super init]) {
      	// ...
        
        // 根据Router页面传入的ip 或 选中的 "以JS模式加载" -> ip 分别取值为 传入的ip值和"",可以此来增加标志位表示当前模式是否为动态化模式
      	// 本地读取时,需要手动的将ip置为nil,并保留标志位作为动态运行的标志
        _useJS = NO;
        if (ip) {
            _useJS = YES;
            ip = nil;
        }
        // ...
    }
    return self;
}

2、实现KuiklyRenderViewControllerDelegatorDelegate协议中的fetchContextCodeWithPageName方法、ContextUrl方法以及assetsPathUrl方法

// 实现fetchContextCodeWithPageName方法以加载产物
- (void)fetchContextCodeWithPageName:(NSString *)pageName resultCallback:(KuiklyContextCodeCallback)callback {
    
    if (callback) {
        if (_ip) {
            // js 模式
            // 读取本地js文件,加载js字符串
            NSString *filePath = [[NSBundle mainBundle] pathForResource:@"nativevue2" ofType:@"js"];
            NSError *error = nil;
            NSString *jsContent = [NSString stringWithContentsOfFile:filePath
                                                            encoding:NSUTF8StringEncoding
                                                               error:&error];
            // 返回js字符串
            callback(jsContent, nil);
        } else {
            // framework 模式
            // 返回对应framework名字,当前Framework 产物名称为shared,可在Kuikly项目的shared目录下的build.gradle 中修改此名称
            callback(@"shared", nil);
        }
    }
}
// 必须实现
- (NSURL *)contextUrl{
    //  配置js模式当前js产物所在路径
}
// 必须实现
- (NSURL *)assetsPathUrl {
    // 配置js 模式资源目录assets 的路径
}

// 补充(可选):若js模式下,还需要访问其他Bundle目录内的资源,可增加实现resourceFolderUrlForKuikly方法提供Bundle路径
- (NSURL *)resourceFolderUrlForKuikly:(NSString *)pageName {

}
上次编辑于:
Kuikly AI助手