LiquidCore-headers 0.7.10

LiquidCore-headers 0.7.10

Eric Lange维护。



  • 作者:
  • Eric Lange

液体核心项目

Download

NPM

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

LiquidCore还为Android开发者提供了一个方便的方法,让他们可以在应用内部执行原始JavaScript,就像iOS开发者可以用原生JavaScriptCore执行JavaScript一样。

安装

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

在您的项目根目录中,您必须有file package.json 文件。如果您还没有,可以通过以下方式创建它:

$ npm init

并按照向导中的步骤操作。

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

$ npm i liquidcore
$ npx liquidcore init

init步骤将添加一些实用脚本和liquidcore对象到您的package.json文件中。它还将创建一个名为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查找文件时的一个特色。这些文件必须在安装时存在,否则即使后来创建,它们也不会在pod中可用。因此,在添加新的entry之后,只需再次执行这部分即可。

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

自动打包

0.7.0+版本中的一个新特性是能够在应用程序构建过程中自动打包JavaScript文件。这是在上述的gradle-config和/或pod-config步骤中进行的配置。打包选项存储在本地package.json文件中的liquidcore属性中。一个典型的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,并且你的应用程序是以调试模式构建的,它将首先尝试从服务器获取打包文件。如果服务器不可用,它将使用构建时自动打包的打包文件。在生产模式下,它将始终使用打包的打包文件。

使用

微服务API

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

Android Kotlin

iPhone 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。package.json中的liquidcore.entry中引用的任何javascript入口文件将在每个构建时自动捆绑。默认情况下,初始化脚本创建并捆绑example.js,但您可以轻松更改此。

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

Android Kotlin

iPhone 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

iPhone 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文件系统冲突。文件系统详细信息请参阅此处

Play with 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-only(非原生)模块并将它们正常安装为require。捆绑器将所有代码打包成一个单一文件。

API 文档

Android Javadocs (liquidcore-Nodejs)

Android Javadocs (liquidcore-V8)

iOS Objective-C/Swift

授权协议

版权所有 (c) 2014 - 2020 LiquidPlayer

许可协议:MIT。详情见 LICENSE.md