LiquidCore 0.7.10

LiquidCore 0.7.10

Eric Lange维护。



LiquidCore 0.7.10

  • 作者
  • Eric Lange

LiquidCore项目

Download

NPM

LiquidCore使Node.js虚拟机能够在Android和iOS应用中运行。它提供完整的运行环境,包括虚拟文件系统。

LiquidCore还提供了一种方便的方法,让Android开发者可以在他们的应用中执行原生JavaScript,正如iOS开发者可以使用JavaScriptCore那样。

安装

步骤 1:确保您的项目已配置为使用npm

在您的项目根目录下,您必须有一个package.json文件。如果您还没有,可以运行以下命令来创建它

$ npm init

并根据向导中的步骤操作。

步骤 2:安装LiquidCore并配置package.json

$ npm i liquidcore
$ npx liquidcore init

init步骤将在您的package.json文件中添加一些实用脚本和liquidcore对象。它还会创建一个名为example.js的示例服务,该服务将打包进您的应用中。您可以通过在package.json中编辑liquidcore.entry属性来更改/添加要打包的文件。

第3步:配置您的移动应用项目

Android

iOS

$ npx liquidcore gradle-config --module=<app>

其中<app>是您的应用程序模块的名称(在Android Studio中默认为'app')。

$ npx liquidcore pod-config --target=<target> --podfile=<podfile>
$ npx liquidcore bundler --platform=ios
$ pod install

其中<target>是您的XCode项目目标,而<podfile>是您的应用Podfile的路径。

关于iOS的说明

LiquidCore需要使用Cocoapods,因此请确保您已设置好项目以使用Podfile。**注意**:您的Podfile必须包含use_frameworks!指令。如果您尚未使用Cocoapods,可以创建一个如下的简单版本

platform :ios, '11.0'
use_frameworks!

target '<TARGET>' do
end

其中<TARGET>是您的xcodeproj的名称(不带.xcodeproj扩展名)。

此外,每次您在package.json中添加一个新的liquidcore.entry点时,您必须首先运行捆绑器,然后再次运行pod install。这是Cocoapods如何查找文件的奇怪之处。这些文件必须在安装时存在,否则即使稍后创建了这些文件,它们也不会在库中可用。因此,在添加新的entry后,只需再次执行此部分即可

$ npx liquidcore bundler --platform=ios
$ pod install

自动打包

0.7.0+ 版本新增加的一项特性是能够在应用程序构建过程中自动打包 JavaScript 文件。这通过 gradle-config 和/或 pod-config 步骤进行配置。打包选项存储在位于 liquidcore 属性中的本地 package.json 文件中。一个典型的 liquidcore 对象可能看起来像这样

  "liquidcore": {
    "entry": [
      "example.js",
      "index.js"
    ],
    "gradle_options": {
      "module": "app"
    },
    "bundler_output": {
      "android": "app/src/main/res/raw",
      "ios": ".liquidcore/ios_bundle"
    },
    "bundler_options": {
      "minify": false
    },
    "pod_options": {
      "dev": true,
      "target": "TestApp"
    }
  }

要包含一个新的打包文件,只需将入口点 JavaScript 文件放入 entry 数组属性。LiquidCore 将在构建过程中为每个 entry 生成一个打包文件。

如果你的应用程序有非标准配置,你可能需要更改这些值中的某些值。例如,Android 的 bundler_output 假定你的资源目录位于 <app-module>/src/main/res。这是 Android Studio 的默认设置。如果你已经将其更改,则需要更新此属性。

打包是测试和打包你的 JavaScript 项目的便捷方式。打包器使用 Metro 将所有必需的 node 模块打包成单个文件,可将其作为您应用中的资源进行打包。如果你正在运行 Android 模拟器或 iOS 模拟器,你可以在您的开发机上运行本地服务器并通过在项目根目录中执行 npx liquidcore server 来热编辑您的 JavaScript 代码。如果你正在使用 Bundle API(以下将描述),并且你的应用程序以调试模式编译,它将首先尝试从服务器获取打包文件。如果服务器不可用,它将使用构建时间自动打包的打包文件。在发行模式下,它将始终使用打包的打包文件。

使用方法

《MicroService》API

微型服务不过是一个独立的 Node.js 实例,其启动代码通过 URI 引用。例如

Android Kotlin

iOS Swift

val uri = MicroService.Bundle(androidContext, "example")
val service = MicroService(androidContext, uri)
service.start()
import LiquidCore
...
let url = LCMicroService.bundle("example")
let service = LCMicroService(url: url)
service?.start()

服务URI可以指向服务器URL或本地资源。对于LiquidCore自动与您的应用程序捆绑的服务,您可以使用MicroService.Bundle()LCMicroService.bundle()方法生成正确的URI。在liquidcore.entry中的package.json中引用的任何javascript入口文件都会自动与每个构建捆绑在一起。默认情况下,初始化脚本创建和捆绑example.js,但您可以轻松更改此设置。

在设置Node.js环境之后,微服务可以与宿主应用程序通信。这可以通过在构造函数中添加一个启动监听器来实现。

Android Kotlin

iOS Swift

val uri = MicroService.Bundle(androidContext, "example")
val startListener = MicroService.ServiceStartListener {
    // .. The environment is live, but the startup
    // JS code (from the URI) has not been executed yet.
}
val service = MicroService(androidContext, uri,
    startListener)
service.start()

遵守LCMicroServiceDelegate协议

let service = LCMicroService(url:url,
                        delegate:self)
service?.start()
...
func onStart(_ service: LCMicroService) {
    // .. The environment is live, but the
    // startup JS code (from the URI) has
    // not been executed yet.
}

微服务通过简单的EventEmitter接口与宿主通信,该接口命名为LiquidCore。例如,在您的JavaScript启动代码中

LiquidCore.emit('my_event', {foo: "hello, world", bar: 5, l337 : ['a', 'b'] })

在应用侧,宿主应用程序可以监听事件

Android Kotlin

iOS Swift

val listener = MicroService.EventListener {
    service, event, payload ->
    android.util.Log.i("Event:" + event,
        payload.getString("foo"))
    // logs: I/Event:my_event: hello, world
}
service.addEventListener("my_event", listener)

遵守LCMicroServiceEventListener协议

service.addEventListener("my_event", listener:self)
...
func onEvent(_ service: LCMicroService, event: String,
               payload: Any?) {
    var p = (payload as! Dictionary<String,AnyObject>)
    NSLog(format:"Event: %@: %@", args:event, p["foo"]);
    // logs: Event:my_event: hello, world
}

同样,微服务可以监听来自宿主的回调事件

Android Kotlin

iOS Swift

val payload = JSONObject()
payload.put("hallo", "die Weld")
service.emit("host_event", payload)
var payload = ["hallo" : "die Weld"]
service.emitObject("host_event", object:payload)

然后,在 JavaScript 中

LiquidCore.on('host_event', function(msg) {
   console.log('Hallo, ' + msg.hallo)
})

LiquidCore 创建了一个便捷的虚拟文件系统,以便微服务实例不会无意或恶意地相互干扰,也不会与 Android/iOS 文件系统其余部分冲突。文件系统详细说明见此处

玩转 example.js

按照上述说明操作后,LiquidCore 将自动捆绑一个名为 example.js 的文件,如下所示

const {LiquidCore} = require('liquidcore')

// A micro service will exit when it has nothing left to do.  So to
// avoid a premature exit, set an indefinite timer.  When we
// exit() later, the timer will get invalidated.
setInterval(()=>{}, 1000)

console.log('Hello, World!')

// Listen for a request from the host for the 'ping' event
LiquidCore.on( 'ping', () => {
    // When we get the ping from the host, respond with "Hello, World!"
    // and then exit.
    LiquidCore.emit( 'pong', { message: 'Hello, World from LiquidCore!' } )
    process.exit(0)
})

// Ok, we are all set up.  Let the host know we are ready to talk
LiquidCore.emit( 'ready' )

以下是从应用中交互此 JavaScript 代码的示例。注意,Android 上的 hello_text 和 iOS 上的 textBox 是 UI 元素,其设置在此处未显示。

Android Kotlin

iOS Swift

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import org.liquidplayer.service.MicroService

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState:
                        Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val hello = findViewById<TextView>(
        R.id.hello_text)

    val readyListener = MicroService.EventListener {
      service, _, _ -> service.emit("ping")
    }
    val pongListener = MicroService.EventListener {
      _, _, jsonObject ->
      val message = jsonObject.getString("message")
      runOnUiThread { hello.text = message }
    }
    val startListener =
        MicroService.ServiceStartListener{
      service ->
      service.addEventListener("ready", readyListener)
      service.addEventListener("pong", pongListener)
    }
    val uri = MicroService.Bundle(this, "example")
    val service = MicroService(this, uri,
                               startListener)
    service.start()
  }
}
import UIKit
import LiquidCore

class ViewController: UIViewController,
  LCMicroServiceDelegate,
  LCMicroServiceEventListener {

  @IBOutlet weak var textBox: UITextField!

  override func viewDidLoad() {
    super.viewDidLoad()

    let url = LCMicroService.bundle("example")
    let service = LCMicroService(url: url,
                                delegate: self)
    service?.start()
  }

  func onStart(_ service: LCMicroService) {
    service.addEventListener("ready",listener: self)
    service.addEventListener("pong", listener: self)
  }

  func onEvent(_ service: LCMicroService,
                   event: String,
                 payload: Any?) {
    if event == "ready" {
      service.emit("ping")
    } else if event == "pong" {
      let p = (payload as! Dictionary<String,AnyObject>)
      let message = p["message"] as! String
      DispatchQueue.main.async {
        self.textBox.text = message
      }
    }
  }
}

您可以用这个作为创建自己的服务的指南。您可以使用 npm install 安装大多数仅使用 JavaScript(非本地)的模块,并且可以作为正常安装它们。打包器会将所有代码打包成一个文件。

API 文档

Android Javadocs (liquidcore-Nodejs)

Android Javadocs (liquidcore-V8)

iOS Objective-C/Swift

许可证

版权所有 (c) 2014 - 2020 LiquidPlayer

遵照 MIT 许可证分发。详情请见 LICENSE.md