M3(批2): DeviceProvider + NetworkProvider

T-M3-02 DeviceProvider:getTime/getphonestate(call.getCallState)/getmarketname/getothername(按名查本地配置)/
        getOther/getcompareCode(暂返 '0' 待接版本决策) 同步返回;getbattery→getBattery(batteryInfo.batterySOC/100)、
        getwifiLevel→getwifiLevel(wifiManager 信号 0~4)、getphoneInfo→getphoneinfo(deviceInfo;IMEI/IMSI/MAC 鸿蒙受限留空) 出站推送。
        裸串 vs JSON、出站命名陷阱(getphoneinfo 小写/getBattery 大写)逐字对齐
T-M3-03 NetworkProvider:getnetwork 同步返回 1无网/2WiFi/3移动(connection.getDefaultNet+bearerTypes);
        connection 订阅 netAvailable/netLost/netCapabilitiesChange 变化时出站广播 getnetwork;onDestroy 注销
module.json5 增 GET_NETWORK_INFO/GET_WIFI_INFO;组装根装配二者

devecocli build 通过。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lanterngamescn
2026-06-25 19:19:54 +08:00
parent 59b000ce7a
commit 7af1d7e834
5 changed files with 212 additions and 1 deletions
+4 -1
View File
@@ -6,7 +6,8 @@
* RoomStubProvider/PayStubProvider,§6.5),契约 handler 名/数量不变。 * RoomStubProvider/PayStubProvider,§6.5),契约 handler 名/数量不变。
*/ */
import { CapabilityProvider, EchoSampleProvider, RoomStubProvider, PayStubProvider, import { CapabilityProvider, EchoSampleProvider, RoomStubProvider, PayStubProvider,
VibrateProvider, ClipboardProvider, AppSystemProvider } from 'feature_capabilities'; VibrateProvider, ClipboardProvider, AppSystemProvider, DeviceProvider,
NetworkProvider } from 'feature_capabilities';
export function buildCapabilities(): CapabilityProvider[] { export function buildCapabilities(): CapabilityProvider[] {
return [ return [
@@ -15,6 +16,8 @@ export function buildCapabilities(): CapabilityProvider[] {
new AppSystemProvider(), // orientation/browser/finsh/openApplyDownloadpath/notification new AppSystemProvider(), // orientation/browser/finsh/openApplyDownloadpath/notification
new VibrateProvider(), // vibrator/repeatvibrator/canclevibrator new VibrateProvider(), // vibrator/repeatvibrator/canclevibrator
new ClipboardProvider(), // gameCopytext/gamepastetext new ClipboardProvider(), // gameCopytext/gamepastetext
new DeviceProvider(), // getTime/getphonestate/getbattery/getwifiLevel/getphoneInfo/getmarketname/getothername/getOther/getcompareCode
new NetworkProvider(), // getnetwork + 出站广播
// —— 暂缓能力占位桩(§6.5)—— // —— 暂缓能力占位桩(§6.5)——
new RoomStubProvider(), new RoomStubProvider(),
new PayStubProvider(), new PayStubProvider(),
+6
View File
@@ -58,6 +58,12 @@
}, },
{ {
"name": "ohos.permission.VIBRATE" "name": "ohos.permission.VIBRATE"
},
{
"name": "ohos.permission.GET_NETWORK_INFO"
},
{
"name": "ohos.permission.GET_WIFI_INFO"
} }
] ]
} }
+2
View File
@@ -12,3 +12,5 @@ export { RoomStubProvider, PayStubProvider } from './src/main/ets/providers/Stub
export { VibrateProvider } from './src/main/ets/providers/VibrateProvider'; export { VibrateProvider } from './src/main/ets/providers/VibrateProvider';
export { ClipboardProvider } from './src/main/ets/providers/ClipboardProvider'; export { ClipboardProvider } from './src/main/ets/providers/ClipboardProvider';
export { AppSystemProvider } from './src/main/ets/providers/AppSystemProvider'; export { AppSystemProvider } from './src/main/ets/providers/AppSystemProvider';
export { DeviceProvider } from './src/main/ets/providers/DeviceProvider';
export { NetworkProvider } from './src/main/ets/providers/NetworkProvider';
@@ -0,0 +1,118 @@
/**
* 设备/系统信息能力(契约 §8.3T-M3-02)。裸串 vs JSON 严格区分。
* 同步返回(responseCallback):getTime/getphonestate/getmarketname/getothername/getOther/getcompareCode
* 异步出站推送:getbattery→getBattery、getwifiLevel→getwifiLevel、getphoneInfo→getphoneinfo(全小写)
*
* 注:HarmonyOS 隐私约束下 IMEI/IMSI/MAC 不可获取,PhoneInfoBean 对应字段留空(与平台能力一致)。
* 需 module.json5 声明 GET_WIFI_INFOgetwifiLevel)。
*/
import { deviceInfo } from '@kit.BasicServicesKit';
import { batteryInfo } from '@kit.BasicServicesKit';
import { call } from '@kit.TelephonyKit';
import { wifiManager } from '@kit.ConnectivityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { BridgeController } from 'feature_bridge';
import { InboundHandlers, OutboundHandlers, PhoneInfoBean, WifiLevelResp } from 'contracts';
import { ConfigManager, AppConfig } from 'domain_resource';
import { Logger } from 'common';
import { CapabilityContext, CapabilityProvider } from '../core/CapabilityProvider';
export class DeviceProvider implements CapabilityProvider {
readonly name: string = 'device';
private readonly log: Logger = Logger.tag('DeviceProvider');
private bridge: BridgeController | undefined = undefined;
private config: ConfigManager | undefined = undefined;
register(bridge: BridgeController, ctx: CapabilityContext): void {
this.bridge = bridge;
this.config = ctx.config;
bridge.registerHandler(InboundHandlers.GetTime, (_d: string, cb: (resp: string) => void) => {
cb(Date.now().toString());
});
bridge.registerHandler(InboundHandlers.GetPhoneState, (_d: string, cb: (resp: string) => void) => {
call.getCallState().then((s: call.CallState) => cb(`${s}`)).catch(() => cb('0'));
});
bridge.registerHandler(InboundHandlers.GetMarketName, (_d: string, cb: (resp: string) => void) => {
cb(this.local().market);
});
bridge.registerHandler(InboundHandlers.GetOther, (_d: string, cb: (resp: string) => void) => {
cb(this.local().other);
});
bridge.registerHandler(InboundHandlers.GetOtherName, (data: string, cb: (resp: string) => void) => {
cb(this.lookupConfig(data));
});
bridge.registerHandler(InboundHandlers.GetCompareCode, (_d: string, cb: (resp: string) => void) => {
// TODO(M3)1=本地 appversion>网络 app_version/0=否,需接 StartupOrchestrator 的版本决策;暂安全返回 '0'
cb('0');
});
bridge.registerHandler(InboundHandlers.GetBattery, (_d: string, _cb: (resp: string) => void) => {
this.pushBattery();
});
bridge.registerHandler(InboundHandlers.GetWifiLevel, (_d: string, _cb: (resp: string) => void) => {
this.pushWifiLevel();
});
bridge.registerHandler(InboundHandlers.GetPhoneInfo, (_d: string, _cb: (resp: string) => void) => {
this.pushPhoneInfo();
});
}
private local(): AppConfig {
return this.config!.getLocal();
}
/** getothername:按配置名取本地配置值。 */
private lookupConfig(name: string): string {
const c: AppConfig = this.local();
switch (name) {
case 'agent': return c.agent;
case 'channel': return c.channel;
case 'gamedir': return c.gamedir;
case 'gamestart': return c.gamestart;
case 'appversion': return c.appversion;
case 'market': return c.market;
case 'gameid': return c.gameid;
case 'weburl': return c.weburl;
case 'gameconfig': return c.gameconfig;
case 'other': return c.other;
case 'tuiguang': return c.tuiguang;
default: return '';
}
}
/** getBattery:电量 float 0~1。 */
private pushBattery(): void {
const soc: number = batteryInfo.batterySOC; // 0~100
const level: number = Math.max(0, Math.min(100, soc)) / 100;
this.bridge?.callHandler(OutboundHandlers.GetBattery, `${level}`);
}
/** getwifiLevel{ssidname, signalLevel(0~4)}。失败回安全默认(H5 不卡死)。 */
private pushWifiLevel(): void {
wifiManager.getLinkedInfo()
.then((info: wifiManager.WifiLinkedInfo) => {
const level: number = wifiManager.getSignalLevel(info.rssi, info.band);
const resp: WifiLevelResp = { ssidname: info.ssid ?? '', signalLevel: level };
this.bridge?.callHandler(OutboundHandlers.GetWifiLevel, JSON.stringify(resp));
})
.catch((e: BusinessError) => {
this.log.w(`getwifiLevel failed: ${e.code} ${e.message}`);
const resp: WifiLevelResp = { ssidname: '', signalLevel: 0 };
this.bridge?.callHandler(OutboundHandlers.GetWifiLevel, JSON.stringify(resp));
});
}
/** getphoneinfo(出站全小写):PhoneInfoBean。IMEI/IMSI/MAC 受限留空。 */
private pushPhoneInfo(): void {
const bean: PhoneInfoBean = {
PhoneVersion: deviceInfo.osFullName,
PhoneAdresseMAC: '',
PhoneModel: deviceInfo.productModel,
PhoneDeviceBrand: deviceInfo.brand,
PhoneProvidersName: '',
PhoneIMEI: '',
PhoneIMSI: '',
};
this.bridge?.callHandler(OutboundHandlers.GetPhoneInfo, JSON.stringify(bean));
}
}
@@ -0,0 +1,82 @@
/**
* 网络状态能力(契约 §8.3/§9T-M3-03)。@ohos.net.connection。
* - getnetwork:同步返回 int 裸串(1 无网 / 2 WiFi / 3 移动)。
* - 出站 getnetwork:网络变化时广播同样的 int 裸串。
* 需 module.json5 声明 GET_NETWORK_INFO。
*/
import { connection } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { BridgeController } from 'feature_bridge';
import { InboundHandlers, OutboundHandlers } from 'contracts';
import { Logger } from 'common';
import { CapabilityContext, CapabilityProvider } from '../core/CapabilityProvider';
/** 网络码(契约:1 无网 / 2 WiFi / 3 移动)。 */
const NET_NONE: string = '1';
const NET_WIFI: string = '2';
const NET_MOBILE: string = '3';
export class NetworkProvider implements CapabilityProvider {
readonly name: string = 'network';
private readonly log: Logger = Logger.tag('NetworkProvider');
private bridge: BridgeController | undefined = undefined;
private conn: connection.NetConnection | undefined = undefined;
register(bridge: BridgeController, _ctx: CapabilityContext): void {
this.bridge = bridge;
bridge.registerHandler(InboundHandlers.GetNetwork, (_d: string, cb: (resp: string) => void) => {
this.currentNetwork().then((code: string) => cb(code)).catch(() => cb(NET_NONE));
});
this.subscribe();
}
onDestroy(): void {
const c = this.conn;
if (c !== undefined) {
c.unregister((_e: BusinessError) => { });
this.conn = undefined;
}
}
/** 取当前网络码。 */
private async currentNetwork(): Promise<string> {
const has: boolean = await connection.hasDefaultNet();
if (!has) {
return NET_NONE;
}
const netHandle: connection.NetHandle = await connection.getDefaultNet();
const cap: connection.NetCapabilities = await connection.getNetCapabilities(netHandle);
const bearers: number[] = cap.bearerTypes ?? [];
if (bearers.includes(connection.NetBearType.BEARER_WIFI)) {
return NET_WIFI;
}
if (bearers.includes(connection.NetBearType.BEARER_CELLULAR)) {
return NET_MOBILE;
}
return NET_NONE;
}
/** 订阅网络变化,变化时出站推送 getnetwork。 */
private subscribe(): void {
try {
const conn: connection.NetConnection = connection.createNetConnection();
this.conn = conn;
conn.on('netAvailable', () => this.broadcast());
conn.on('netLost', () => this.bridge?.callHandler(OutboundHandlers.GetNetwork, NET_NONE));
conn.on('netCapabilitiesChange', () => this.broadcast());
conn.register((e: BusinessError) => {
if (e) {
this.log.w(`net register failed: ${e.code} ${e.message}`);
}
});
} catch (e) {
this.log.w(`subscribe failed: ${(e as BusinessError).message}`);
}
}
private broadcast(): void {
this.currentNetwork()
.then((code: string) => this.bridge?.callHandler(OutboundHandlers.GetNetwork, code))
.catch(() => { });
}
}