Android 集成指南
本文介绍了如何在 Android 应用程序中使用 InkView 集成 Ink 引擎。
前置条件
- Android Studio (Ladybug 或更高版本)
- Android SDK (API Level 24+)
- NDK (r25c 或更高版本)
- Rust Toolchain (1.70+)
1. 添加依赖
首先,你需要获取 Ink Android 库 (AAR)。
- 从 Android Build Workflow 下载最新的 AAR 构建产物。
- 将下载的 AAR 文件(例如
ink-debug.aar)放置在应用的libs目录下。
Gradle 设置
在应用的 build.gradle.kts 中:
dependencies {
// Ink Android 核心库
implementation(files("libs/ink-debug.aar"))
// 用于 Java 和 Native 层之间 IPC 通信的高效 CBOR 序列化
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.14.2")
// 为 Jackson 序列化提供 Kotlin 支持
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.2")
}2. 添加 InkView 到布局
你可以将 InkView 直接添加到 XML 布局文件中,或通过代码动态创建。
XML 布局
<com.rokid.jsai.ink.InkView
android:id="@+id/inkView"
android:layout_width="match_parent"
android:layout_height="match_parent" />动态创建
val inkView = InkView(context)
layout.addView(inkView)3. 初始化并打开小程序
在你的 Activity 或 Fragment 中,初始化 InkView 并打开小程序。
class MainActivity : AppCompatActivity() {
private lateinit var inkView: InkView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
inkView = findViewById(R.id.inkView)
// 从本地目录打开小程序
val appPath = filesDir.absolutePath + "/mini-app"
inkView.open(appPath)
}
}4. 实现系统能力
Ink 依赖宿主应用提供多媒体、网络和语音等系统能力。你需要实现相应的接口。
4.1 实现能力
以下是实现 MediaCapability 接口来处理多媒体请求的示例。其他能力(网络、语音)遵循类似的模式。
inkView.addCapability(object : InkView.MediaCapability {
override fun startAudioRecording(
reqId: String,
targetId: String,
options: InkView.AudioRecordingOptions,
callback: InkView.VoidCallback
) {
try {
// 初始化并开始录音
myAudioRecorder.start(options.sampleRate)
callback.success()
} catch (e: Exception) {
callback.error(-1, e.message ?: "未知错误")
}
}
override fun stopAudioRecording(reqId: String, callback: InkView.VoidCallback) {
myAudioRecorder.stop()
callback.success()
}
// 类似地实现其他方法(暂停、恢复、拍照)...
})4.2 分发事件
Ink 支持两种类型的事件分发:特定目标事件 (Target-Specific Events) 和 全局事件 (Global Events)。
特定目标事件
这些事件被分发到特定目标(例如录音会话或网络 Socket)。你需要提供 targetId(或 handle),它通常通过能力实现方法传递给你(例如,startAudioRecording 提供 targetId)。
dispatchEvent(targetId: String, eventData: MediaEventData)
向特定媒体会话分发媒体相关事件。
- 参数:
targetId: 目标组件/会话的 UUID(在startAudioRecording中接收)。eventData: 特定的媒体事件负载(例如MediaEventData.AudioRecordingStarted,MediaEventData.AudioFrameRecorded)。
dispatchEvent(targetId: String, eventData: NetworkingEventData)
向特定 Socket 连接分发网络相关事件。
- 参数:
targetId: Socket 句柄的 UUID(在openSocket中接收)。eventData: 网络事件负载(例如NetworkingEventData.Data)。
示例:
// 分发媒体事件(例如,录音开始)
inkView.dispatchEvent(recordingSessionId, InkView.MediaEventData.AudioRecordingStarted)
// 分发网络事件(例如,收到数据)
val data = "Hello".toByteArray()
inkView.dispatchEvent(socketHandle, InkView.NetworkingEventData.Data(data))全局事件
这些事件不绑定到特定目标,影响全局状态或是通用输入事件。
dispatchEvent(type: InputEventType, code: String, timestamp: Long)
分发全局输入事件(例如键盘按键)。
- 参数:
type: 输入事件类型(InputEventType.KeyUp或InputEventType.KeyDown)。code: 键值字符串(例如 "KeyA", "Enter")。timestamp: 毫秒级事件时间戳。
示例:
// 分发全局输入事件
inkView.dispatchEvent(InkView.InputEventType.KeyDown, "KeyA", System.currentTimeMillis())4.3 系统能力参考
本节详细介绍了可用的系统能力、其方法以及应分发的事件。
多媒体 (InkView.MediaCapability)
处理录音和相机操作。
inkView.addCapability(object : InkView.MediaCapability {
override fun startAudioRecording(
reqId: String,
targetId: String,
options: InkView.AudioRecordingOptions,
callback: InkView.VoidCallback
) {
// 开始录音...
callback.success()
}
// 实现其他方法...
})方法:
startAudioRecording(reqId: String, targetId: String, options: AudioRecordingOptions, callback: VoidCallback)
请求开始录音。
- 参数:
reqId: 唯一请求 ID。targetId: 录音会话的 UUID。options: 配置(采样率、通道数等)。callback: 报告成功或错误。
stopAudioRecording(reqId: String, callback: VoidCallback)
请求停止录音。
pauseAudioRecording(reqId: String, callback: VoidCallback)
请求暂停录音。
resumeAudioRecording(reqId: String, callback: VoidCallback)
请求恢复录音。
takePhoto(reqId: String, options: TakePhotoOptions, callback: PhotoCallback)
请求拍照。
- 回调:
success(data: ByteArray, mimeType: String)
事件 (InkView.MediaEventData):
| 事件名称 | 数据类型 | 描述 |
|---|---|---|
AudioRecordingStarted | Unit | 录音已开始。 |
AudioRecordingStopped | String | 录音已停止(带有可选原因/ID)。 |
AudioRecordingPaused | Unit | 录音已暂停。 |
AudioRecordingResumed | Unit | 录音已恢复。 |
AudioFrameRecorded | ByteArray | 新的音频帧数据。 |
AudioRecordingError | String | 发生错误。 |
AudioRecordingInterruptionBegin | Unit | 录音中断(例如来电)。 |
AudioRecordingInterruptionEnd | Unit | 中断结束。 |
网络 (InkView.NetworkingCapability)
处理 Socket 操作。
inkView.addCapability(object : InkView.NetworkingCapability {
override fun openSocket(
reqId: String,
handle: String,
name: String,
port: Int,
isSsl: Boolean,
callback: InkView.VoidCallback
) {
// 打开 Socket...
callback.success()
}
// 实现其他方法...
})方法:
openSocket(reqId: String, handle: String, name: String, port: Int, isSsl: Boolean, callback: VoidCallback)
请求打开 Socket 连接。
- 参数:
reqId: 唯一请求 ID。handle: 此 Socket 的唯一 UUID。name: 主机名或 IP 地址。port: 端口号。isSsl: 是否使用 SSL/TLS。callback: 报告成功或错误。
closeSocket(reqId: String, handle: String, callback: VoidCallback)
请求关闭 Socket。
send(reqId: String, handle: String, data: ByteArray, callback: VoidCallback)
请求通过 Socket 发送数据。
事件 (InkView.NetworkingEventData):
| 事件名称 | 数据类型 | 描述 |
|---|---|---|
Data | ByteArray | 从 Socket 接收到的数据。 |
语音 (InkView.SpeechCapability)
处理文本转语音 (TTS) 和自动语音识别 (ASR)。
inkView.addCapability(object : InkView.SpeechCapability {
override fun playTts(
reqId: String,
text: String,
callback: InkView.VoidCallback
) {
// 播放 TTS...
callback.success()
}
override fun startAsr(
reqId: String,
callback: InkView.StringCallback
) {
// 开始 ASR...
callback.success("识别到的文本")
}
})方法:
playTts(reqId: String, text: String, callback: VoidCallback)
请求播放 TTS。
- 参数:
reqId: 唯一请求 ID。text: 要朗读的文本。callback: 报告完成。
startAsr(reqId: String, callback: StringCallback)
请求开始语音识别。
- 回调:
success(text: String)返回识别到的文本。
事件:
- 无特定事件;结果通过回调返回。
6. 生命周期管理
确保正确处理 InkView 的生命周期。
override fun onDestroy() {
super.onDestroy()
// SurfaceView 销毁时会自动清理原生资源,
// 但你可以在这里确保其他清理工作。
}