跳到主要内容

从内存载入

JadeView 2.0 支持从内存直接加载 JAPK 包,无需本地文件系统。适用于将 JAPK 数据嵌入可执行文件或从网络下载后直接使用的场景。

本页介绍内存载入相关 API。如需从本地文件加载,请参阅 从本地载入。 构建 JAPK 混淆包请使用 JadePack 桌面客户端。


概述

JadeView_load_from_bytes 从内存加载 JAPK 包,内部根据魔数和公钥设置自动选择加载路径:

  • 设置了公钥 → 只接受 JAPK v2 签名包,验证签名后解密加载
  • 未设置公钥 → 接受 混淆包 v2,解混淆后加载

💡 提示:签名包和混淆包均由 JadePack 构建。签名包需先通过 JadeView_set_public_key 注入公钥再加载。

格式魔数说明构建工具
JAPK v2 签名包JAPKV002Ed25519 签名 + AES-256-GCM 加密JadePack
混淆包 v2JPKBIN02SHA256 动态密钥派生 + 3 层可逆变换JadePack

关键安全约束:公钥设置后,签名包加载失败 绝不会回退 到混淆包逻辑。


核心 API

JadeView_set_public_key

设置 Ed25519 公钥。调用后 JadeView_load_from_bytes 将只接受签名包。

int JadeView_set_public_key(const char* public_key);

参数:

  • public_key string - Base64 编码的 Ed25519 公钥(44 字符)

返回值:

  • 0 - 成功
  • 负数 - 错误码

JadeView_load_from_bytes

从内存加载 JAPK 包。

int JadeView_load_from_bytes(const uint8_t* japk_data, size_t data_size);

参数:

  • japk_data uint8_t* - JAPK 文件数据指针
  • data_size size_t - 数据大小(字节)

返回值:

  • 0 - 加载成功
  • 负数 - 错误码,详见下方错误码表

调用顺序

  1. JadeView_init — 初始化运行时
  2. JadeView_set_public_key — (可选)设置公钥
  3. JadeView_load_from_bytes — 加载 JAPK 数据

JadeView_is_loaded

检查 JAPK 包是否已成功加载。

int JadeView_is_loaded(void);

返回值:

  • 1 - 已加载
  • 0 - 未加载

JadeView_get_app_signature

返回当前加载包的 app_signature 字符串。

char* JadeView_get_app_signature(void);

返回值:

  • 非 NULL - 应用标识字符串,调用方需用 jade_text_free 释放

JadeView_get_signature_info

返回签名信息 JSON。仅签名包加载成功后有值。

char* JadeView_get_signature_info(void);

返回值:

  • 非 NULL - 签名信息 JSON 字符串,调用方需用 jade_text_free 释放

JadeView_unload

清除加载状态,释放内存中的 JAPK 数据。

int JadeView_unload(void);

错误码

常量说明
0JADEVIEW_JAPK_OK成功
-1JADEVIEW_JAPK_ERROR_INVALID_PARAM无效参数(空指针/大小为0)
-2JADEVIEW_JAPK_ERROR_NOT_INITIALIZED未调用 JadeView_init
-3JADEVIEW_JAPK_ERROR_LOAD_FAILED加载失败
-4JADEVIEW_JAPK_ERROR_INVALID_FORMAT无效/不支持的格式
-5JADEVIEW_JAPK_ERROR_INVALID_SIGNATURE签名验证失败
-6JADEVIEW_JAPK_ERROR_APP_MISMATCHapp_signature/app_name 不匹配
-7JADEVIEW_JAPK_ERROR_DECRYPT_FAILED解密/解混淆失败
-8JADEVIEW_JAPK_ERROR_UNSIGNED_NOT_ALLOWED签名包缺少签名
-9JADEVIEW_JAPK_ERROR_MISSING_PUBLIC_KEY未设置公钥
-10JADEVIEW_JAPK_ERROR_INVALID_PUBLIC_KEY公钥格式无效
-11JADEVIEW_JAPK_ERROR_POLICY_DENIED安全策略拒绝
-12JADEVIEW_JAPK_ERROR_NOT_LOADED未加载

事件

加载过程通过 jade_on 注册的回调异步通知:

japk-load-success

加载成功时触发,回调收到 JSON 数据:

{
"app_signature": "com.example.app",
"app_name": "MyApp",
"asar_size": 1048576,
"type": "signed"
}
字段签名包混淆包
app_signature
app_name
asar_size
type"signed""scrambled"

japk-load-failed

加载失败时触发,回调收到纯文本错误消息,如 "Signature verification failed"


使用示例

C 语言

#include "jadeview.h"

void load_from_memory_example() {
// 1. 初始化
JadeView_init(1, NULL, NULL, "MyApp", "com.example.app", 0);

// 2. 读取 JAPK 文件到内存
FILE* f = fopen("app.japk", "rb");
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
fseek(f, 0, SEEK_SET);
uint8_t* data = malloc(size);
fread(data, 1, size, f);
fclose(f);

// 3. 从内存加载(混淆包,无需公钥)
int rc = JadeView_load_from_bytes(data, size);
if (rc != 0) {
printf("加载失败: %d\n", rc);
free(data);
return;
}

// 4. 获取协议 URL(内存加载时传入空字符串)
char url_buffer[256];
set_protocol_service_path("", url_buffer, sizeof(url_buffer));
// url_buffer 内容类似: https://myapp.local/

// 5. 创建窗口使用该 URL
WebViewWindowOptions options = {
.title = "JAPK 内存加载",
.width = 800,
.height = 600,
.frame_style = "normal"
};
create_webview_window(url_buffer, 0, &options, NULL);

free(data);
}

签名包加载

// 设置公钥后,只接受签名包
JadeView_set_public_key("QeeOu5LQdQooeyOID6h/ChFEo5RhbAFoKgslznp5Nbk=");

int rc = JadeView_load_from_bytes(data, size);
// 此时只接受 JAPKV002 签名包

Python (ctypes)

import ctypes
from ctypes import c_char_p, c_int, c_uint8, c_size_t, POINTER

dll = ctypes.WinDLL("JadeView.dll")

dll.JadeView_init.argtypes = [c_int, c_char_p, c_char_p, c_char_p, c_char_p, c_int]
dll.JadeView_init.restype = c_int

dll.JadeView_load_from_bytes.argtypes = [POINTER(c_uint8), c_size_t]
dll.JadeView_load_from_bytes.restype = c_int

dll.JadeView_is_loaded.argtypes = []
dll.JadeView_is_loaded.restype = c_int

# 1. 初始化
dll.JadeView_init(1, None, b"./data", b"MyApp", b"com.example.app", 0)

# 2. 读取 JAPK 到内存
with open("app.japk", "rb") as f:
japk_data = f.read()

# 3. 内存加载(混淆包)
data_ptr = (c_uint8 * len(japk_data)).from_buffer_copy(japk_data)
rc = dll.JadeView_load_from_bytes(data_ptr, len(japk_data))
if rc != 0:
raise RuntimeError(f"JadeView_load_from_bytes failed: {rc}")

# 4. 获取协议 URL(内存加载时传入空字符串)
dll.set_protocol_service_path.argtypes = [c_char_p, c_char_p, c_size_t]
dll.set_protocol_service_path.restype = c_int

url_buffer = ctypes.create_string_buffer(256)
dll.set_protocol_service_path(b"", url_buffer, 256)
print(f"协议 URL: {url_buffer.value.decode()}")

# 5. 使用该 URL 创建窗口
loaded = dll.JadeView_is_loaded()
print(f"JAPK loaded: {loaded}")

签名包加载需额外设置公钥:

dll.JadeView_set_public_key.argtypes = [c_char_p]
dll.JadeView_set_public_key.restype = c_int

dll.JadeView_set_public_key(b"QeeOu5LQdQooeyOID6h/ChFEo5RhbAFoKgslznp5Nbk=")
rc = dll.JadeView_load_from_bytes(data_ptr, len(japk_data))

完整调用时序

调用方 JadeView DLL
│ │
├─ JadeView_init ────────────────►│ 初始化
│ │
├─ JadeView_set_public_key ──────►│ (可选) 设置验证公钥
│ │
├─ jade_on("japk-load-success")──►│ 注册成功回调
├─ jade_on("japk-load-failed") ──►│ 注册失败回调
│ │
├─ JadeView_load_from_bytes ─────►│ 魔数检测 → 签名/混淆 → ASAR
│ │
│ ◄── japk-load-success ────────┤ 异步事件
│ │
├─ set_protocol_service_path("")─►│ 获取协议 URL
│ ◄── url_buffer ───────────────┤ jade://myapp.local/
│ │
├─ create_webview_window(url) ───►│ 创建窗口
│ │
├─ run_message_loop ─────────────►│ 进入事件循环