@ayden-fc2/riffle-bridge-web 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -24
- package/dist/index.d.mts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +11 -0
- package/dist/index.mjs +11 -0
- package/package.json +1 -1
- package/src/controllers/index.ts +21 -0
package/README.md
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## 1. tweaks和RiffleBridge用法总览
|
|
4
4
|
|
|
5
|
-
本文档为当前Web应用提供Bridge
|
|
5
|
+
本文档为当前Web应用提供Bridge使用指导,分为必选的tweaks和可选的RiffleBridge两个API,从而与app应用通信。
|
|
6
6
|
|
|
7
7
|
**安装依赖:**
|
|
8
8
|
```bash
|
|
9
9
|
npm install @ayden-fc2/riffle-bridge-web
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
tweaks用于联通web应用与
|
|
12
|
+
tweaks用于联通web应用与app应用的自定义参数,传递支持颜色、数值、文本、布尔、选项类型的JsonSchema格式的tweaksConfig,原则上web应用内的颜色、数值、文本、布尔、选项都要通过tweaks层配置,从而保证app应用能够响应式控制,使用参考文章第二节。
|
|
13
13
|
|
|
14
|
-
RiffleBridge用于调用震动、音频、相机等模块的
|
|
14
|
+
RiffleBridge用于调用震动、音频、相机等模块的app应用功能,展开对应文章第三节各个模块,根据所需要实现的web应用功能,按需参考模块取用即可;
|
|
15
15
|
|
|
16
16
|
## 2. tweaks 用法
|
|
17
17
|
|
|
@@ -23,20 +23,20 @@ RiffleBridge用于调用震动、音频、相机等模块的native功能,展
|
|
|
23
23
|
|
|
24
24
|
```
|
|
25
25
|
const tweaksConfig = {
|
|
26
|
-
// 颜色类型 -
|
|
26
|
+
// 颜色类型 - app应用 端显示颜色选择器
|
|
27
27
|
color: { name: '颜色', type: 'color', value: '#667eea' },
|
|
28
28
|
|
|
29
|
-
// 数值类型 -
|
|
29
|
+
// 数值类型 - app应用 端显示滑块
|
|
30
30
|
size: { name: '大小', type: 'number', value: 150, min: 50, max: 300 },
|
|
31
31
|
opacity: { name: '透明度', type: 'number', value: 1, min: 0, max: 1, step: 0.1 },
|
|
32
32
|
|
|
33
|
-
// 文本类型 -
|
|
33
|
+
// 文本类型 - app应用 端显示文本输入框
|
|
34
34
|
title: { name: '标题', type: 'string', value: 'Hello World' },
|
|
35
35
|
|
|
36
|
-
// 布尔类型 -
|
|
36
|
+
// 布尔类型 - app应用 端显示开关
|
|
37
37
|
enabled: { name: '启用', type: 'boolean', value: true },
|
|
38
38
|
|
|
39
|
-
// 选项类型 -
|
|
39
|
+
// 选项类型 - app应用 端显示下拉选择器
|
|
40
40
|
mode: { name: '模式', type: 'select', value: 'normal', options: ['normal', 'fast', 'slow'] },
|
|
41
41
|
vibration: { name: '震动', type: 'select', value: 'medium', options: [
|
|
42
42
|
{ label: '轻', value: 'light' },
|
|
@@ -48,7 +48,7 @@ const tweaksConfig = {
|
|
|
48
48
|
|
|
49
49
|
### 2.2 初始化(必须传入React实例)
|
|
50
50
|
|
|
51
|
-
通过 { React } 参数显式传入初始化,保证web和
|
|
51
|
+
通过 { React } 参数显式传入初始化,保证web和app应用数据联通,响应式更新,初始化代码如下:
|
|
52
52
|
|
|
53
53
|
```
|
|
54
54
|
import React, { useMemo } from 'react';
|
|
@@ -64,7 +64,7 @@ const tweaks = useMemo(() => createTweaks(tweaksConfig, { React }), []);
|
|
|
64
64
|
|
|
65
65
|
```
|
|
66
66
|
function Demo() {
|
|
67
|
-
// .useState() 自动响应式订阅,
|
|
67
|
+
// .useState() 自动响应式订阅,app应用 修改时自动重渲染
|
|
68
68
|
const color = tweaks.color.useState();
|
|
69
69
|
const size = tweaks.size.useState();
|
|
70
70
|
|
|
@@ -76,7 +76,7 @@ function Demo() {
|
|
|
76
76
|
|
|
77
77
|
## 3. RiffleBridge用法
|
|
78
78
|
|
|
79
|
-
通过 `RiffleBridge` 类调用
|
|
79
|
+
通过 `RiffleBridge` 类调用app应用功能:
|
|
80
80
|
|
|
81
81
|
```
|
|
82
82
|
import { RiffleBridge } from '@ayden-fc2/riffle-bridge-web';
|
|
@@ -112,7 +112,7 @@ await bridge.haptic.intensity(0.5);
|
|
|
112
112
|
- **y轴**:正值指向设备顶部
|
|
113
113
|
- **z轴**:正值指向屏幕外(朝向用户)
|
|
114
114
|
|
|
115
|
-
> iOS 和 Android 原始坐标系不同,Bridge 已在
|
|
115
|
+
> iOS 和 Android 原始坐标系不同,Bridge 已在 app应用 层自动处理,WebView 端收到的数据保持一致。
|
|
116
116
|
|
|
117
117
|
```typescript
|
|
118
118
|
// 启动传感器
|
|
@@ -160,14 +160,14 @@ const tilt = bridge.utils.getTiltDirection(x, y);
|
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
### 3.3 音频模块(录音、播放)
|
|
163
|
-
> 特别注意拿到的uri文件资源是
|
|
163
|
+
> 特别注意拿到的uri文件资源是app应用文件路径,当前web应用无法直接播放音频,请参考录音模块代码,先调用readAsBase64转码再播放!
|
|
164
164
|
|
|
165
165
|
**播放模块:**
|
|
166
166
|
|
|
167
167
|
单例模式实现,主要用于不需要用户交互就直接播放的背景音乐等,点击音效等仍由web应用本身实现
|
|
168
168
|
|
|
169
169
|
```
|
|
170
|
-
// 播放,支持传入 local://xxx 或 file://xxx 的
|
|
170
|
+
// 播放,支持传入 local://xxx 或 file://xxx 的app应用本地路径,或 https://xxx 的url网址
|
|
171
171
|
await bridge.audio.playOnline({ uri: playUri });
|
|
172
172
|
|
|
173
173
|
// 播放并循环(适用于背景音乐)
|
|
@@ -208,14 +208,14 @@ console.log('时长:', result.durationMillis / 1000, '秒');
|
|
|
208
208
|
|
|
209
209
|
// 保存录音(以aydens-voice为例,实际可以替换为web应用的独特键,或者result.uri的独特文件名)
|
|
210
210
|
if (result?.uri) {
|
|
211
|
-
// 保存文件到
|
|
211
|
+
// 保存文件到app应用应用并记录map
|
|
212
212
|
await bridge.fileStorage.addCustomFileMapping('local://recording/aydens-voice', result.uri);
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
// 1. 后续让
|
|
215
|
+
// 1. 后续让app应用播放
|
|
216
216
|
await bridge.audio.playOnline({ uri: 'local://recording/aydens-voice' });
|
|
217
217
|
|
|
218
|
-
// 2. 后续直接让web
|
|
218
|
+
// 2. 后续直接让web应用播放
|
|
219
219
|
const audioData = await bridge.fileStorage.readAsBase64(result.uri);
|
|
220
220
|
const audio = new Audio(audioData.dataUrl); // dataUrl 已是完整 'data:audio/mp4;base64,...'
|
|
221
221
|
audio.play();
|
|
@@ -227,7 +227,7 @@ audio.play();
|
|
|
227
227
|
|
|
228
228
|
### 3.4 相机模块(实时相机、拍照、相册、闪光灯)
|
|
229
229
|
|
|
230
|
-
>> 特别注意拿到的uri文件资源是
|
|
230
|
+
>> 特别注意拿到的uri文件资源是app应用件路径,当前web应用无法直接渲染,请参考下方**拍照/相册**的代码,先调用readAsBase64转码再渲染!
|
|
231
231
|
|
|
232
232
|
**实时相机**
|
|
233
233
|
|
|
@@ -244,7 +244,7 @@ document.getElementById('root')!.style.background = 'transparent';
|
|
|
244
244
|
|
|
245
245
|
// 拍照
|
|
246
246
|
// ⚠️ 拍照后不要直接渲染,参考下方**拍照/相册**的代码,先调用readAsBase64转码再渲染!
|
|
247
|
-
// ⚠️ 拍照后如果需要保存,也参考下方**拍照/相册**的代码调用
|
|
247
|
+
// ⚠️ 拍照后如果需要保存,也参考下方**拍照/相册**的代码调用app应用的文件存储模块保存并记录map
|
|
248
248
|
const photo = await bridge.camera.takePhoto();
|
|
249
249
|
|
|
250
250
|
// 切换摄像头
|
|
@@ -292,14 +292,14 @@ await bridge.camera.setFilter('none');
|
|
|
292
292
|
// 1. 拍照(以aydens-demo-photo为例,实际web应用使用picked.uri文件名或组特的key)
|
|
293
293
|
const photo = await bridge.fileStorage.takePhoto();
|
|
294
294
|
if (!photo?.cancelled) {
|
|
295
|
-
// 保存文件到
|
|
295
|
+
// 保存文件到app应用并记录map
|
|
296
296
|
await bridge.fileStorage.addCustomFileMapping('local://photos/aydens-demo-photo', photo.uri);
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
// 2. 或从相册选择(以aydens-photo为例,实际web应用使用picked.uri文件名或组特的key)
|
|
300
300
|
const picked = await bridge.fileStorage.pickFromGallery();
|
|
301
301
|
if (!picked?.cancelled) {
|
|
302
|
-
// 保存文件到
|
|
302
|
+
// 保存文件到app应用并记录map
|
|
303
303
|
await bridge.fileStorage.addCustomFileMapping('local://photos/aydens-demo-photo', picked.uri);
|
|
304
304
|
}
|
|
305
305
|
|
|
@@ -309,6 +309,43 @@ const base64 = await bridge.fileStorage.readAsBase64('local://photos/aydens-demo
|
|
|
309
309
|
<img src={`data:image/jpeg;base64,${base64}`} />
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
+
**保存到系统相册**
|
|
313
|
+
|
|
314
|
+
将图片或视频保存到用户的系统相册(会请求系统相册写入权限)
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
// 拍照后保存到系统相册
|
|
318
|
+
const photo = await bridge.fileStorage.takePhoto();
|
|
319
|
+
if (!photo?.cancelled) {
|
|
320
|
+
// 保存到系统相册(默认相册名 'Riffle')
|
|
321
|
+
const result = await bridge.fileStorage.saveToGallery(photo.uri);
|
|
322
|
+
console.log('保存成功:', result.filename);
|
|
323
|
+
|
|
324
|
+
// 或指定自定义相册名
|
|
325
|
+
const result2 = await bridge.fileStorage.saveToGallery(photo.uri, 'MyApp相册');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// 也可以保存已缓存的文件到系统相册
|
|
329
|
+
const cached = await bridge.fileStorage.getLocalFileByUrl('local://photos/aydens-demo-photo');
|
|
330
|
+
if (cached?.exists && cached.uri) {
|
|
331
|
+
await bridge.fileStorage.saveToGallery(cached.uri);
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
返回值类型:
|
|
336
|
+
```typescript
|
|
337
|
+
interface SaveToGalleryResult {
|
|
338
|
+
success: boolean; // 是否成功
|
|
339
|
+
assetId?: string; // 系统相册资产ID
|
|
340
|
+
uri?: string; // 保存后的URI
|
|
341
|
+
filename?: string; // 文件名
|
|
342
|
+
mediaType?: string; // 媒体类型 'photo' | 'video'
|
|
343
|
+
width?: number; // 图片宽度
|
|
344
|
+
height?: number; // 图片高度
|
|
345
|
+
duration?: number; // 视频时长(秒)
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
312
349
|
**闪光灯**
|
|
313
350
|
|
|
314
351
|
闪光灯必须打开实时相机才能调用,参考实时相机的说明。
|
|
@@ -316,7 +353,7 @@ const base64 = await bridge.fileStorage.readAsBase64('local://photos/aydens-demo
|
|
|
316
353
|
当应用需要闪光灯而不要实时相机时,可以使用非透明web应用背景来遮挡实时相机
|
|
317
354
|
|
|
318
355
|
### 3.5 文件存储模块
|
|
319
|
-
>> 特别注意拿到的uri文件资源是
|
|
356
|
+
>> 特别注意拿到的uri文件资源是app应用文件路径,当前web应用无法直接渲染图片或播放音频,请参考下方代码,先调用readAsBase64转码再渲染或播放!相机&录音等模块也都有联动说明
|
|
320
357
|
|
|
321
358
|
文件映射系统维护了一个MAP映射表,支持本地文件和网络资源两种存储,web应用要根据需求选择使用哪种
|
|
322
359
|
|
|
@@ -332,7 +369,7 @@ if (!photo?.cancelled) {
|
|
|
332
369
|
// 查询(查看是否存在)
|
|
333
370
|
const cached = await bridge.fileStorage.getLocalFileByUrl('local://avatar/123');
|
|
334
371
|
|
|
335
|
-
// 拿到base64
|
|
372
|
+
// 拿到base64
|
|
336
373
|
const base64 = await bridge.fileStorage.readAsBase64('local://avatar/123');
|
|
337
374
|
// 在 Web 中渲染
|
|
338
375
|
<img src={`data:image/jpeg;base64,${base64}`} />
|
|
@@ -349,7 +386,7 @@ console.log(result.cached ? '使用缓存' : '已下载', result.uri);
|
|
|
349
386
|
const base64 = await bridge.fileStorage.readAsBase64(url);
|
|
350
387
|
```
|
|
351
388
|
|
|
352
|
-
**读取资源并解码base64,从
|
|
389
|
+
**读取资源并解码base64,从app应用传入web应用**
|
|
353
390
|
```
|
|
354
391
|
// uri为mapRecord记录值
|
|
355
392
|
const base64 = await bridge.fileStorage.readAsBase64(mapRecord);
|
package/dist/index.d.mts
CHANGED
|
@@ -405,6 +405,21 @@ declare class FileStorageController {
|
|
|
405
405
|
added: boolean;
|
|
406
406
|
}>;
|
|
407
407
|
readAsBase64(uriOrKey: string): Promise<Base64Result>;
|
|
408
|
+
/**
|
|
409
|
+
* 保存图片/视频到系统相册
|
|
410
|
+
* @param uri 文件 URI(支持 file:// 或 local:// 路径)
|
|
411
|
+
* @param albumName 相册名称(默认 'AIGames')
|
|
412
|
+
*/
|
|
413
|
+
saveToGallery(uri: string, albumName?: string): Promise<{
|
|
414
|
+
success: boolean;
|
|
415
|
+
assetId?: string;
|
|
416
|
+
uri?: string;
|
|
417
|
+
filename?: string;
|
|
418
|
+
mediaType?: string;
|
|
419
|
+
width?: number;
|
|
420
|
+
height?: number;
|
|
421
|
+
duration?: number;
|
|
422
|
+
}>;
|
|
408
423
|
}
|
|
409
424
|
interface PlayOptions {
|
|
410
425
|
uri: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -405,6 +405,21 @@ declare class FileStorageController {
|
|
|
405
405
|
added: boolean;
|
|
406
406
|
}>;
|
|
407
407
|
readAsBase64(uriOrKey: string): Promise<Base64Result>;
|
|
408
|
+
/**
|
|
409
|
+
* 保存图片/视频到系统相册
|
|
410
|
+
* @param uri 文件 URI(支持 file:// 或 local:// 路径)
|
|
411
|
+
* @param albumName 相册名称(默认 'AIGames')
|
|
412
|
+
*/
|
|
413
|
+
saveToGallery(uri: string, albumName?: string): Promise<{
|
|
414
|
+
success: boolean;
|
|
415
|
+
assetId?: string;
|
|
416
|
+
uri?: string;
|
|
417
|
+
filename?: string;
|
|
418
|
+
mediaType?: string;
|
|
419
|
+
width?: number;
|
|
420
|
+
height?: number;
|
|
421
|
+
duration?: number;
|
|
422
|
+
}>;
|
|
408
423
|
}
|
|
409
424
|
interface PlayOptions {
|
|
410
425
|
uri: string;
|
package/dist/index.js
CHANGED
|
@@ -419,6 +419,17 @@ var FileStorageController = class {
|
|
|
419
419
|
async readAsBase64(uriOrKey) {
|
|
420
420
|
return this.core.send("fileStorage", "readAsBase64", { uriOrKey });
|
|
421
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* 保存图片/视频到系统相册
|
|
424
|
+
* @param uri 文件 URI(支持 file:// 或 local:// 路径)
|
|
425
|
+
* @param albumName 相册名称(默认 'AIGames')
|
|
426
|
+
*/
|
|
427
|
+
async saveToGallery(uri, albumName = "Riffle") {
|
|
428
|
+
return this.core.send("fileStorage", "saveToGallery", {
|
|
429
|
+
saveUri: uri,
|
|
430
|
+
albumName
|
|
431
|
+
});
|
|
432
|
+
}
|
|
422
433
|
};
|
|
423
434
|
var AudioController = class {
|
|
424
435
|
constructor(core, fileStorage) {
|
package/dist/index.mjs
CHANGED
|
@@ -377,6 +377,17 @@ var FileStorageController = class {
|
|
|
377
377
|
async readAsBase64(uriOrKey) {
|
|
378
378
|
return this.core.send("fileStorage", "readAsBase64", { uriOrKey });
|
|
379
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* 保存图片/视频到系统相册
|
|
382
|
+
* @param uri 文件 URI(支持 file:// 或 local:// 路径)
|
|
383
|
+
* @param albumName 相册名称(默认 'AIGames')
|
|
384
|
+
*/
|
|
385
|
+
async saveToGallery(uri, albumName = "Riffle") {
|
|
386
|
+
return this.core.send("fileStorage", "saveToGallery", {
|
|
387
|
+
saveUri: uri,
|
|
388
|
+
albumName
|
|
389
|
+
});
|
|
390
|
+
}
|
|
380
391
|
};
|
|
381
392
|
var AudioController = class {
|
|
382
393
|
constructor(core, fileStorage) {
|
package/package.json
CHANGED
package/src/controllers/index.ts
CHANGED
|
@@ -301,6 +301,27 @@ export class FileStorageController {
|
|
|
301
301
|
async readAsBase64(uriOrKey: string): Promise<Base64Result> {
|
|
302
302
|
return this.core.send<Base64Result>('fileStorage', 'readAsBase64', { uriOrKey });
|
|
303
303
|
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 保存图片/视频到系统相册
|
|
307
|
+
* @param uri 文件 URI(支持 file:// 或 local:// 路径)
|
|
308
|
+
* @param albumName 相册名称(默认 'AIGames')
|
|
309
|
+
*/
|
|
310
|
+
async saveToGallery(uri: string, albumName = 'Riffle'): Promise<{
|
|
311
|
+
success: boolean;
|
|
312
|
+
assetId?: string;
|
|
313
|
+
uri?: string;
|
|
314
|
+
filename?: string;
|
|
315
|
+
mediaType?: string;
|
|
316
|
+
width?: number;
|
|
317
|
+
height?: number;
|
|
318
|
+
duration?: number;
|
|
319
|
+
}> {
|
|
320
|
+
return this.core.send('fileStorage', 'saveToGallery', {
|
|
321
|
+
saveUri: uri,
|
|
322
|
+
albumName,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
304
325
|
}
|
|
305
326
|
|
|
306
327
|
// ============================================
|