252 lines
8.4 KiB
Markdown
252 lines
8.4 KiB
Markdown
# bluememe-utils
|
||
|
||
Cordova plugin for OutSystems 11 mobile apps.
|
||
|
||
功能:
|
||
|
||
- 保存或连接指定 WiFi 热点
|
||
- Firebase Cloud Messaging 推送通知
|
||
- Touch ID / Face ID / Android biometric 解锁,并把解锁结果通知给应用
|
||
|
||
插件 ID:`bluememe-utils`
|
||
|
||
JS 全局对象:
|
||
|
||
- `BluememeUtils`
|
||
- `cordova.plugins.bluememeUtils`
|
||
|
||
## Install
|
||
|
||
在 OutSystems 11 的 extensibility configuration 中添加插件仓库或本地包后,可使用下面的参数覆盖 Firebase 配置。
|
||
|
||
```json
|
||
{
|
||
"plugin": {
|
||
"url": "bluememe-utils",
|
||
"variables": {
|
||
"ANDROID_FIREBASE_APP_ID": "1:000000000000:android:xxxxxxxxxxxxxxxx",
|
||
"ANDROID_FIREBASE_API_KEY": "AIza...",
|
||
"ANDROID_FIREBASE_PROJECT_ID": "your-firebase-project",
|
||
"ANDROID_FIREBASE_SENDER_ID": "000000000000",
|
||
"ANDROID_FIREBASE_STORAGE_BUCKET": "your-firebase-project.appspot.com",
|
||
"IOS_FIREBASE_GOOGLE_APP_ID": "1:000000000000:ios:xxxxxxxxxxxxxxxx",
|
||
"IOS_FIREBASE_API_KEY": "AIza...",
|
||
"IOS_FIREBASE_PROJECT_ID": "your-firebase-project",
|
||
"IOS_FIREBASE_GCM_SENDER_ID": "000000000000",
|
||
"IOS_FIREBASE_STORAGE_BUCKET": "your-firebase-project.appspot.com",
|
||
"IOS_FACE_ID_USAGE_DESCRIPTION": "Use Face ID to unlock this application."
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
也可以让宿主 App 提供并处理标准 Firebase 配置文件:
|
||
|
||
- Android:`google-services.json`
|
||
- iOS:`GoogleService-Info.plist`
|
||
|
||
如果宿主工程已经由 OutSystems、MABS 配置或其他插件初始化 Firebase,本插件会复用已有的 default Firebase app。否则建议使用上面的 plugin variables,让本插件在运行时手动初始化 Firebase。
|
||
|
||
## JavaScript API
|
||
|
||
所有方法都使用 Cordova callback 风格,适合在 OutSystems client action 中封装。
|
||
|
||
```js
|
||
BluememeUtils.getDeviceInfo(function (info) {
|
||
console.log(info.deviceKey);
|
||
}, error);
|
||
```
|
||
|
||
`getDeviceInfo` 返回:
|
||
|
||
```json
|
||
{
|
||
"deviceKey": "generated-and-persisted-uuid",
|
||
"platform": "Android",
|
||
"appIdentifier": "com.company.app",
|
||
"appVersion": "1.0.0",
|
||
"buildNumber": "1",
|
||
"osVersion": "15",
|
||
"sdkVersion": 35,
|
||
"deviceModel": "Google Pixel 8",
|
||
"manufacturer": "Google",
|
||
"brand": "google",
|
||
"model": "Pixel 8",
|
||
"locale": "ja-JP",
|
||
"timeZone": "Asia/Tokyo"
|
||
}
|
||
```
|
||
|
||
`deviceKey` 首次调用时生成并保存在本地,用于标识当前 App 安装实例。App 卸载或清除数据后会重新生成。iOS 不返回 `sdkVersion`、`manufacturer`、`brand`,但会返回 `systemName`。
|
||
|
||
```js
|
||
BluememeUtils.requestWifiPermission(success, error);
|
||
|
||
BluememeUtils.saveWifi({
|
||
ssid: "MyHotspot",
|
||
password: "password123",
|
||
security: "wpa2"
|
||
}, success, error);
|
||
|
||
BluememeUtils.connectWifi({
|
||
ssid: "MyHotspot",
|
||
password: "password123",
|
||
security: "wpa2"
|
||
}, success, error);
|
||
|
||
BluememeUtils.removeWifi({ ssid: "MyHotspot", password: "password123", security: "wpa2" }, success, error);
|
||
BluememeUtils.disconnectWifi(success, error);
|
||
```
|
||
|
||
WiFi options:
|
||
|
||
- `ssid`:必填
|
||
- `password`:开放网络可省略
|
||
- `security`:`open`、`wep`、`wpa2`、`wpa3`,默认按是否存在 password 推断为 `open` 或 `wpa2`
|
||
- `hiddenSsid`:可选;Android 支持隐藏 SSID;iOS 15+ 会设置 `NEHotspotConfiguration.hidden`
|
||
- `bssid`:可选,仅 Android 10+ 临时连接使用
|
||
- `joinOnce`:可选,仅 iOS;`connectWifi` 默认 `true`,`saveWifi` 默认 `false`
|
||
|
||
## Push Notifications
|
||
|
||
```js
|
||
BluememeUtils.requestPushPermission(success, error);
|
||
BluememeUtils.getPushPermissionStatus(success, error);
|
||
BluememeUtils.getFirebaseToken(function (result) {
|
||
console.log(result.token);
|
||
}, error);
|
||
|
||
BluememeUtils.subscribeToTopic("news", success, error);
|
||
BluememeUtils.unsubscribeFromTopic("news", success, error);
|
||
|
||
BluememeUtils.startNotificationListener(function (event) {
|
||
if (event.type === "token") {
|
||
console.log(event.token);
|
||
}
|
||
if (event.type === "notification") {
|
||
console.log(event.notification);
|
||
}
|
||
if (event.type === "notificationOpened") {
|
||
console.log(event.notification);
|
||
}
|
||
}, error);
|
||
|
||
BluememeUtils.getInitialNotification(success, error);
|
||
BluememeUtils.stopNotificationListener(success, error);
|
||
```
|
||
|
||
`getPushPermissionStatus` 只读取当前系统通知状态,不弹授权框。可用于填充后端 `NotificationsEnabled`。
|
||
|
||
返回示例:
|
||
|
||
```json
|
||
{
|
||
"type": "notification",
|
||
"platform": "Android",
|
||
"enabled": true,
|
||
"granted": true,
|
||
"runtimePermissionGranted": true,
|
||
"appNotificationsEnabled": true,
|
||
"authorizationStatus": "authorized",
|
||
"missing": []
|
||
}
|
||
```
|
||
|
||
推荐注册 token 前调用:
|
||
|
||
```js
|
||
BluememeUtils.getPushPermissionStatus(function (status) {
|
||
var notificationsEnabled = status.enabled === true;
|
||
}, error);
|
||
```
|
||
|
||
事件也会派发到 `window`:
|
||
|
||
- `bluememeutils.token`
|
||
- `bluememeutils.notification`
|
||
- `bluememeutils.notificationOpened`
|
||
- `bluememeutils.unlock`
|
||
|
||
也可以用插件内置监听器:
|
||
|
||
```js
|
||
BluememeUtils.on("unlock", function (event) {
|
||
console.log(event.unlocked);
|
||
});
|
||
```
|
||
|
||
## Biometric Unlock
|
||
|
||
```js
|
||
BluememeUtils.isBiometricAvailable(success, error);
|
||
|
||
BluememeUtils.unlockWithBiometrics({
|
||
reason: "Unlock application",
|
||
title: "Unlock",
|
||
subtitle: "",
|
||
description: "",
|
||
cancelText: "Cancel",
|
||
fallbackTitle: "Use Passcode",
|
||
allowDeviceCredential: true
|
||
}, function (result) {
|
||
console.log(result.unlocked, result.biometryType);
|
||
}, error);
|
||
```
|
||
|
||
`biometryType` 可能值:
|
||
|
||
- iOS:`face`、`touch`、`none`、`biometric`
|
||
- Android:`face`、`fingerprint`、`iris`、`biometric`
|
||
|
||
## Platform Notes
|
||
|
||
Android WiFi:
|
||
|
||
- Android 10+ 不允许第三方应用静默保存并强制切换系统 WiFi。
|
||
- `saveWifi` 在 Android 10+ 使用 `WifiNetworkSuggestion`,系统可能要求用户批准。
|
||
- `connectWifi` 在 Android 10+ 使用 `WifiNetworkSpecifier`,这是临时连接,通常只绑定当前应用进程网络。
|
||
- Android 9 及以下使用旧 `WifiConfiguration` API,可保存并启用网络。
|
||
- 调用 WiFi API 前先调用 `requestWifiPermission`,并确保系统位置服务开启。
|
||
|
||
iOS WiFi:
|
||
|
||
- 使用 `NEHotspotConfiguration`,当前插件 WiFi 功能要求 iOS 15+。
|
||
- 插件将 iOS deployment target 设置为 `15.0`;如果宿主 App 或构建平台覆盖该值,需要在宿主配置中同步设置 iOS 最低版本为 15.0 或更高。
|
||
- 插件会向 Cordova iOS entitlements 写入 `com.apple.developer.networking.HotspotConfiguration`,但仍必须在 Apple Developer App ID 中开启 `Hotspot Configuration` capability,并使用包含该 capability 的 provisioning profile 重新构建。
|
||
- 如果 iOS 返回 `NEHotspotConfigurationErrorDomain` code `8` / `internal error`,优先检查 App ID、entitlements、provisioning profile 是否都包含 `Hotspot Configuration`,并确认是在真机前台运行,不是在模拟器中测试。若签名和参数都正确,常见原因是真实热点使用 WPA2/WPA3 transition mode、WPA3 Personal、iPhone Personal Hotspot 默认安全模式,或其他 `NEHotspotConfiguration` 无法表达的 WiFi 能力。
|
||
- iOS 错误结果会包含 `applicationState`、`ssidUtf8Length`、`passwordUtf8Length`、`passwordAsciiPrintable` 等诊断字段;WPA/WPA2 密码建议使用 8-63 位可打印 ASCII 字符。
|
||
- iOS 的 `NEHotspotConfiguration` password initializer 公开支持 WEP/WPA/WPA2 Personal,不提供 WPA3 Personal 参数。iOS 传入 `security` 包含 `wpa3` 时会返回 `UNSUPPORTED_WIFI_SECURITY`。WPA2/WPA3 mixed 通常只能按 `security: "wpa2"` 尝试;如果仍失败,需要用户手动加入,或改用配置描述文件/MDM 流程。
|
||
- iOS 不提供第三方 App 断开当前 WiFi 的公开 API,因此 `disconnectWifi` 在 iOS 返回错误。
|
||
|
||
Firebase:
|
||
|
||
- Android 13+ 需要通知权限,调用 `requestPushPermission`。
|
||
- iOS 需要 Push Notifications capability、Background Modes 中的 Remote notifications,以及 APNs key/certificate 已配置到 Firebase。
|
||
- 如果项目中还有其他推送插件,也可能同时修改 `UNUserNotificationCenterDelegate` 或 Firebase service,需要在真机上确认通知打开事件。
|
||
|
||
Biometric:
|
||
|
||
- iOS Face ID 需要 `NSFaceIDUsageDescription`,可通过 `IOS_FACE_ID_USAGE_DESCRIPTION` 设置。
|
||
- Android 本插件使用平台 `BiometricPrompt`,`unlockWithBiometrics` 支持 Android 9+。
|
||
|
||
## Error Shape
|
||
|
||
错误 callback 返回对象:
|
||
|
||
```json
|
||
{
|
||
"code": "ERROR_CODE",
|
||
"message": "Human readable message"
|
||
}
|
||
```
|
||
|
||
常见错误:
|
||
|
||
- `PERMISSION_REQUIRED`
|
||
- `INVALID_WIFI_OPTIONS`
|
||
- `WIFI_CONNECT_FAILED`
|
||
- `FIREBASE_NOT_CONFIGURED`
|
||
- `FCM_TOKEN_FAILED`
|
||
- `BIOMETRIC_UNAVAILABLE`
|
||
- `AUTHENTICATION_ERROR`
|