Flutter 三方库 sms_sender_plus 的 OpenHarmony 适配实战
Flutter 社区地址: https://atomgit.com/CPF-Flutter/flutter_flutter
适配后仓库地址:https://atomgit.com/oh-flutter/sms_sender_plus
本文记录了将开源 Flutter 三方库
sms_sender_plus适配到 OpenHarmony / HarmonyOS 平台的完整过程,
包含适配思路、代码改动对照、关键决策和踩坑复盘。
一、背景
1.1 三方库简介
sms_sender_plus 是一个 Flutter 社区广泛使用的短信发送插件,提供以下能力:
- Android SIM 卡选择发送 — 通过
TelephonyManager/SmsManager指定订阅(subscription)发送短信,支持双卡设备选卡 - 发送状态回执 — 通过系统广播
SMS_SENT/SMS_DELIVERED上报发送与送达状态,Dart 侧以事件流订阅 - 批量群发 —
sendTextMessages()一次向多个收件人发送,支持长短信自动分片(divideMessage) - iOS 系统短信编辑器 — 基于
MFMessageComposeViewController唤起系统 composer 发送 - 能力与权限探测 —
isSmsAvailable()、checkSmsPermission()、checkPhoneStatePermission()等统一能力/权限查询接口
该三方库最初支持 Android / iOS 两个平台,本次任务将其适配到 OpenHarmony / HarmonyOS 平台。
1.2 适配目标
| 维度 | 要求 |
|---|---|
| 功能一致性 | 全部 8 个方法 + 状态事件流的接口签名与 Android/iOS 完全对齐;在鸿蒙系统权限受限的前提下执行"能力受限"语义,不出现崩溃或悬挂调用 |
| Dart 层零改动 | lib/ 下 Dart 代码零修改,仅通过 pubspec.yaml 新增 ohos 平台注册 |
| 性能 | 方法调用与事件流走标准 MethodChannel / EventChannel,不引入额外桥接层 |
| 工程规范 | 提供完整 ohos/ 插件实现与 example/ohos 示例工程,真机可签名、可编译、可运行;文档、TAG、元信息齐备 |
二、适配路线图
整个适配分为 4 个阶段:
第 1 阶段:项目初始化 ── 用 flutter create 生成 ohos 插件模板骨架(index.ets / HAR 配置)
第 2 阶段:原生实现 ── 将 Android Kotlin 实现逐一翻译为 ArkTS(方法通道 + 事件通道)
第 3 阶段:三方库注册 ── pubspec.yaml 增加 ohos 平台配置,GeneratedPluginRegistrant 自动注册
第 4 阶段:示例验证 ── 生成 example/ohos 工程,签名后真机编译运行验证
三、逐步适配过程
第 1 阶段:项目初始化
使用 Flutter 命令行生成 OHOS 插件模板:
flutter create . --template=plugin --platforms=ohos
该命令自动生成 ohos/ 目录的标准模板结构,包含必要的构建配置和入口文件。
目录结构:
ohos/
├── index.ets # 模块入口,导出插件类
├── oh-package.json5 # HAR 包配置
├── build-profile.json5 # 构建配置
├── hvigorfile.ts # hvigor 构建入口(harTasks)
└── src/main/
├── module.json5 # HAR 模块配置
└── ets/components/plugin/
└── SmsSenderPlusPlugin.ets # 原生插件实现(核心)
关键配置文件:
index.ets(入口导出文件)
import SmsSenderPlusPlugin from './src/main/ets/components/plugin/SmsSenderPlusPlugin';
export default SmsSenderPlusPlugin;
oh-package.json5(包配置)
{
"name": "sms_sender_plus",
"version": "1.0.0",
"description": "HarmonyOS (ohos) platform implementation of sms_sender_plus: a Flutter plugin for SMS capability detection, permission queries, SIM card queries and SMS sending, with capability-limited semantics on OpenHarmony.",
"main": "index.ets",
"author": "坚果 <jianguo@nutpi.net>",
"license": "Apache-2.0",
"dependencies": {}
}
注:
@ohos/flutter_ohos由 Flutter 引擎在构建时自动链接(oh_modules/@ohos/flutter_ohos指向 flutter 引擎缓存的flutter_embedding_debug.har),无需在dependencies中显式声明。
module.json5(HAR 模块配置)
{
"module": {
"name": "sms_sender_plus",
"type": "har",
"deviceTypes": ["default", "tablet"]
}
}
第 2 阶段:原生实现(核心)
这是适配的核心工作。将 Android 平台的 Kotlin 实现逐一翻译为 ArkTS。
2.1 整体架构对比
插件按通信机制分两类。
sms_sender_plus是方法调用型 + 事件流型混合:
MethodChannel('sms_sender_plus')— Dart 主动调用原生(发送 / SIM / 能力 / 权限)EventChannel('sms_sender_plus/status')— 原生主动推送发送/送达状态事件(Android 用系统广播)
方法调用型(MethodChannel + MethodCallHandler):
Android (Kotlin) OHOS (ArkTS)
──────────────────── ────────────────────
class SmsSenderPlusPlugin class SmsSenderPlusPlugin
implements FlutterPlugin, implements FlutterPlugin,
MethodCallHandler MethodCallHandler
import io.flutter.plugin.common. import { FlutterPlugin,
MethodChannel FlutterPluginBinding,
import android.telephony... MethodCall,
MethodCallHandler,
MethodChannel,
MethodResult
} from '@ohos/flutter_ohos'
事件流型(EventChannel + StreamHandler):
Android (Kotlin) OHOS (ArkTS)
──────────────────── ────────────────────
class SmsSenderPlusPlugin class SmsSenderPlusPlugin
implements FlutterPlugin, implements FlutterPlugin,
EventChannel.StreamHandler StreamHandler
BroadcastReceiver (SMS_SENT / (鸿蒙无第三方短信 API,注册空 handler,
SMS_DELIVERED) → eventSink 不产生任何事件,保持流打开)
2.2 通道注册
| 通道 | Android | OHOS |
|---|---|---|
| 方法通道 | MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "sms_sender_plus") | new MethodChannel(binding.getBinaryMessenger(), "sms_sender_plus") |
| 事件通道 | EventChannel(binding.binaryMessenger, "sms_sender_plus/status").setStreamHandler(this) | new EventChannel(binding.getBinaryMessenger(), "sms_sender_plus/status").setStreamHandler(this) |
差异:OHOS 使用
getBinaryMessenger()替代 Android 的getFlutterEngine().getDartExecutor(),接口更简洁;EventChannel构造参数为(messenger, name, codec?),codec默认StandardMethodCodec.INSTANCE,与 Dart 端默认一致,无需显式传入。
2.2.1 事件流型插件的 StreamHandler 生命周期(核心差异)
OHOS 侧实现 StreamHandler 接口的 onListen / onCancel,并持有 EventSink 用于推送事件。
| 时机 | Android | OHOS |
|---|---|---|
| 插件绑定引擎 | onAttachedToEngine 创建 EventChannel | onAttachedToEngine 创建 EventChannel |
| Dart 开始订阅 | onListen → 注册 BroadcastReceiver | onListen → 注册空 handler(鸿蒙无短信事件源) |
| 事件到达 | 广播回调中 eventSink?.success(payload) | 不产生事件(受限语义) |
| Dart 取消订阅 | onCancel → 注销广播 | onCancel → 无可释放资源 |
| 插件解绑引擎 | onDetachedFromEngine → 注销广播 + setStreamHandler(null) | onDetachedFromEngine → setMethodCallHandler(null) |
2.3 原生方法实现对照
| 方法 | Android 实现 | OHOS 实现 | 返回值 |
|---|---|---|---|
isSmsAvailable | TelephonyManager.isSmsCapable | 恒 false | bool |
checkSmsPermission | ContextCompat.checkSelfPermission(SEND_SMS) | 恒 false | bool |
requestSmsPermission | ActivityCompat.requestPermissions + 结果监听 | 恒 false(不弹窗) | bool |
checkPhoneStatePermission | ContextCompat.checkSelfPermission(READ_PHONE_STATE) | 恒 false | bool |
requestPhoneStatePermission | ActivityCompat.requestPermissions + 结果监听 | 恒 false(不弹窗) | bool |
getSimCards | SimCardResolver.getActiveSimCards()(SubscriptionManager + TelephonyManager) | 恒空列表 | List<SimCard> |
sendTextMessage | SmsSender.sendSingle()(SmsManager.sendTextMessage / 分片发送 + PendingIntent 回执) | 恒抛 smsUnavailable 错误 | SmsSendResult |
sendTextMessages | SmsSender.sendBatch()(逐收件人发送) | 恒抛 smsUnavailable 错误 | SmsBatchSendResult |
OHOS 插件核心实现(ArkTS):
export default class SmsSenderPlusPlugin implements FlutterPlugin, MethodCallHandler, StreamHandler {
private channel: MethodChannel | null = null;
private eventChannel: EventChannel | null = null;
getUniqueClassName(): string {
return 'SmsSenderPlusPlugin'
}
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel = new MethodChannel(binding.getBinaryMessenger(), METHOD_CHANNEL_NAME);
this.channel.setMethodCallHandler(this);
this.eventChannel = new EventChannel(binding.getBinaryMessenger(), EVENT_CHANNEL_NAME);
this.eventChannel.setStreamHandler(this);
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
if (this.channel != null) {
this.channel.setMethodCallHandler(null);
this.channel = null;
}
this.eventChannel = null;
}
onMethodCall(call: MethodCall, result: MethodResult): void {
try {
if (call.method == 'sendTextMessage' || call.method == 'sendTextMessages') {
result.error('smsUnavailable', SMS_UNAVAILABLE_MESSAGE, null);
} else if (call.method == 'getSimCards') {
result.success([]);
} else if (call.method == 'isSmsAvailable') {
result.success(false);
} else if (call.method == 'checkSmsPermission' || call.method == 'requestSmsPermission' ||
call.method == 'checkPhoneStatePermission' || call.method == 'requestPhoneStatePermission') {
result.success(false);
} else if (call.method == 'getPlatformVersion') {
result.success('OpenHarmony ^ ^');
} else {
result.notImplemented();
}
} catch (err) {
result.error('sendFailed', `SMS operation failed: ${(err as Error).message}`, null);
}
}
}
2.4 实现差异详解
适配中最关键的问题是:HarmonyOS 未向第三方(normal APL)应用开放短信能力。ohos.permission.SEND_MESSAGES 是 system_basic 级别权限,仅系统应用可申请;订阅(SIM 卡)信息读取也没有公开 API。因此在"照抄 Android 实现"与"受限语义"之间需要决策:
| 方案 | 优点 | 缺点 |
|---|---|---|
受限语义:发送返回 smsUnavailable、权限恒 false、SIM 恒空列表 ✅ | 接口签名与 Dart 契约完全对齐;不崩溃、不悬挂;与 iOS 的"能力受限"分支行为一致;example/文档可给出确定性行为 | 鸿蒙端无法真实发短信 |
| 尝试声明并申请 system_basic 权限 | 理论上可发短信 | 第三方应用安装时即被拒绝授予,requestPermissionsFromUser 不弹窗,纯属无效工作;还会误导用户"授权后即可用" |
关键差异点:鸿蒙端所有"能力型"接口返回确定性结果(
isSmsAvailable=false、权限false、SIM 空列表、发送抛smsUnavailable),与 README 中声明的受限语义自洽;example 层必须先用isSmsAvailable()检测能力再决定是否展示发送入口,不能依赖权限接口控制业务逻辑。
第 3 阶段:三方库注册
在 pubspec.yaml 中添加 OHOS 平台注册:
flutter:
plugin:
platforms:
android:
package: dev.parham.sms_sender_plus
pluginClass: SmsSenderPlusPlugin
ios:
pluginClass: SmsSenderPlusPlugin
ohos: # ← 新增
pluginClass: SmsSenderPlusPlugin # ← 对应 index.ets 默认导出
Flutter 的 OHOS 引擎在构建时会读取 pubspec.yaml 中的 ohos 配置,自动加载 ohos/index.ets 中导出的插件类。注意 pluginClass 必须与实现类的 getUniqueClassName() 返回值大小写完全一致,否则真机启动报 Plugin not found。
第 4 阶段:示例应用创建
在 example/ 目录下生成 OHOS 宿主工程(注意:在 example 目录执行,而非插件根目录):
cd example
flutter create . --platforms=ohos
生成的 example/ohos/ 包含签名配置、SDK 版本、测试模块与 Flutter 运行时资源:
example/ohos/
├── AppScope/app.json5 # 应用配置(bundleName: dev.parham.sms_sender_plus_example)
├── build-profile.json5 # 项目构建配置(signingConfigs、SDK 26)
├── entry/
│ ├── build-profile.json5 # entry 模块(default + ohosTest 双 target)
│ └── src/main/
│ ├── module.json5 # entry 模块配置(EntryAbility + INTERNET 权限)
│ ├── ets/
│ │ ├── entryability/
│ │ │ └── EntryAbility.ets # FlutterAbility + GeneratedPluginRegistrant
│ │ ├── pages/Index.ets # FlutterPage 容器
│ │ └── plugins/GeneratedPluginRegistrant.ets # 自动注册插件(无需手写)
│ └── resources/
│ └── rawfile/buildinfo.json5
│ └── src/ohosTest/ # 测试目录(hypium)
说明:
GeneratedPluginRegistrant.ets由 Flutter 工具根据pubspec.yaml的ohos配置自动生成,会import SmsSenderPlusPlugin from 'sms_sender_plus'并注册到 engine,无需手写。
第 5 阶段:构建验证(HAP)
用 Flutter 工具链构建 HAP,验证原生代码与配置无编译错误:
cd example
flutter build hap --debug
成功产出:build/ohos/hap/entry-default-signed.hap(签名配置使用 DevEco 自动签名 debugKey,SDK 26)。
常见构建错误(踩坑复盘见第八章):
example/ohos未配置签名 →flutter run真机安装失败,需先在 DevEco Studio 中为example/ohos配置自动签名;GeneratedPluginRegistrant.ets缺失 → 先flutter pub get再构建,Flutter 工具会自动生成。
四、完整代码对照
4.1 Android vs OHOS 完整实现对照
| 维度 | Android (Kotlin) | OHOS (ArkTS) |
|---|---|---|
| 语言 | Kotlin | ArkTS (TypeScript 语法) |
| 插件接口 | FlutterPlugin + MethodCallHandler + EventChannel.StreamHandler + ActivityAware | FlutterPlugin + MethodCallHandler + StreamHandler |
| 通道创建 | MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), name) | new MethodChannel(binding.getBinaryMessenger(), name) |
| 短信发送 | SmsManager.sendTextMessage / sendMultipartTextMessage + PendingIntent 回执 | 无第三方 API,返回 smsUnavailable 错误 |
| SIM 读取 | SubscriptionManager.getActiveSubscriptionInfoList() + TelephonyManager.getSimOperator | 无第三方 API,返回空列表 |
| 权限检测 | ContextCompat.checkSelfPermission | 恒 false(system_basic 权限不可申请) |
| 权限申请 | ActivityCompat.requestPermissions + onRequestPermissionsResult 回调 | 恒 false,不弹窗 |
| 能力检测 | TelephonyManager.isSmsCapable | 恒 false |
| 状态事件流 | BroadcastReceiver(SMS_SENT / SMS_DELIVERED)→ eventSink.success | 注册空 handler,保持流打开但不产生事件 |
4.2 关键 ArkTS 语法差异
| Android 语法 | ArkTS 语法 | 备注 |
|---|---|---|
import io.flutter.plugin.common.MethodChannel | import { MethodChannel } from '@ohos/flutter_ohos' | OHOS 使用模块化导入 |
override fun onMethodCall(call, result) | onMethodCall(call: MethodCall, result: MethodResult): void | 方法签名一致,ArkTS 显式标注返回类型 |
result.success(mapOf(...)) / result.error(code, msg, null) | result.success(...) / result.error('smsUnavailable', msg, null) | 语义一致,返回结构对齐 |
null 可空性 | channel: MethodChannel | null = null | ArkTS 用联合类型显式表达可空 |
getFlutterEngine().getDartExecutor() | binding.getBinaryMessenger() | OHOS 通道构造更简洁 |
ActivityAware(activity 绑定) | 无对应场景 | 鸿蒙端无需窗口/上下文,未实现 AbilityAware |
getUniqueClassName() | 必须实现并返回与 pluginClass 一致的类名 | OHOS 插件注册的契约方法 |
五、关键决策说明
决策 1:保持通道名不变
Dart 层 MethodChannel('sms_sender_plus') 与 EventChannel('sms_sender_plus/status') 已固定,OHOS 原生侧必须使用完全相同的通道名。通道名是 Dart 与原生之间的通信契约,改名会导致调用静默失败。
维护策略:通道名作为常量定义在插件文件顶部,与 Dart 端文档同步维护;任何一端改动必须同步另一端并跑通 example 回归。
决策 2:Dart 层零改动
Dart API 通过 MethodChannel.invokeMethod(...) 调用,方法名、参数结构、返回值模型(SmsSendResult / SimCard / SmsStatusEvent)全部保持不变。OHOS 适配零修改 lib/ 代码,仅新增 ohos/ 实现和 pubspec.yaml 平台注册。
维护策略:上游(GitHub 原库)Dart API 变更时,只需同步核对 OHOS 原生侧方法名与返回结构即可。
决策 3:受限语义(鸿蒙 system_basic 权限限制)
HarmonyOS 未向第三方(normal APL)应用开放短信发送、订阅信息读取与短信回执 API(ohos.permission.SEND_MESSAGES 为 system_basic 级别)。因此 OHOS 端执行受限语义:
sendTextMessage/sendTextMessages→ 抛smsUnavailable错误getSimCards→ 空列表;isSmsAvailable→false- 4 个权限接口 → 恒
false,且不发起任何授权请求(发起也无效) statusEvents→ 保持流打开但不产生事件
维护策略:若未来 HarmonyOS 向第三方开放短信 API(或应用以 system_basic 签名),只需替换受限分支为真实实现,Dart 契约不变。
决策 4:能力检测优先(example 层适配)
鸿蒙上权限接口恒 false 且不弹窗,example 若按 Android 的"查权限 → 申请权限"流程走,会反复出现误导性的 “SEND_SMS permission is required”。因此 example 启动时先调用 isSmsAvailable():
- 为
false(鸿蒙)→ 显示 “This device cannot send SMS” 提示横幅、禁用发送按钮、跳过 SIM 加载与权限流程; - 为
true(Android/iOS)→ 行为与原 example 完全一致。
维护策略:example 的能力检测逻辑保持平台无关(只依赖插件公开 API),三端共用同一份 main.dart。
六、测试与验证
测试环境
| 项目 | 版本 |
|---|---|
| Flutter | 3.41.10-ohos-1.0.0(channel [user-branch],git@gitcode.com:CPF-Flutter/flutter_flutter.git) |
| Dart | 随 Flutter 3.41.10-ohos(SDK 约束 >=3.0.0 <4.0.0) |
| HarmonyOS SDK | 26.0.0(API 26),compatibleSdkVersion: 5.1.0(18) / targetSdkVersion: 26.0.0 |
| IDE | DevEco Studio 26.0.0(DS-261.23567.138.36.2600821) |
| 设备 ROM | ALN-AL00 7.0.0.105(SP6C00E105R4P3),OpenHarmony 7.0.0.105(API 26) |
版本获取方式:
| 版本项 | 获取方式 |
|---|---|
| Flutter / Dart | flutter --version |
| HarmonyOS SDK | 读取 example/ohos/build-profile.json5 的 compatibleSdkVersion / targetSdkVersion |
| IDE | /usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" /Applications/DevEco-Studio.app/Contents/Info.plist |
| 设备 ROM | hdc shell param get const.product.software.version |
验证要点
- 静态检查 —
flutter analyze:No issues found(0 error / 0 warning) - HAP 构建 —
cd example && flutter build hap --debug:成功产出build/ohos/hap/entry-default-signed.hap - 插件注册 — 真机启动无
Plugin not found: SmsSenderPlusPlugin错误;GeneratedPluginRegistrant.ets正确导入并注册插件类 - 能力检测 —
isSmsAvailable()返回false,example 显示 “This device cannot send SMS” 横幅且发送按钮禁用(截图见第七章) - 发送接口 —
sendTextMessage/sendTextMessages返回smsUnavailable错误,Dart 层正确捕获为SmsSenderPlusException - SIM / 权限接口 —
getSimCards()返回空列表;4 个权限接口恒false且不弹窗 - 事件流 —
statusEvents订阅无异常,保持打开不产生事件
七、运行效果
适配完成后,真机运行 example 获取运行截图:
cd example
flutter run -d <device_id> --no-resident # 真机部署(也可用 flutter screenshot)

上图左侧为 example 表单(收件人 / 批量 / 消息 / SIM 下拉 / 回执开关),底部 Events 区域展示能力检测后的行为:发送按钮被禁用、显示 “This device cannot send SMS or read SIM cards. HarmonyOS only exposes SMS capabilities to system apps.” 提示横幅,不再出现误导性的权限请求报错。
八、遗留问题与改进方向
踩坑复盘
适配中遇到的实际问题最有价值,复盘如下:
| 踩坑点 | 现象 / 报错 | 根因与解法 |
|---|---|---|
| 权限请求流程误导 | 鸿蒙真机 example 反复显示 “SEND_SMS permission is required” / “READ_PHONE_STATE permission is required” | ohos.permission.SEND_MESSAGES 与电话状态类权限为 system_basic 级别,第三方应用永远申请不到,权限接口恒 false 且不弹窗。解法:example 先调 isSmsAvailable() 做能力检测,false 时显示明确提示、禁用发送按钮、跳过权限流程(commit 20833a5) |
| 插件类名不一致风险 | 真机启动 Plugin not found: XxxPlugin | pubspec.yaml 的 pluginClass 与实现类 getUniqueClassName() 返回值必须大小写完全一致。解法:两者统一为 SmsSenderPlusPlugin |
构建时 GeneratedPluginRegistrant.ets 缺失 | ohos/ 或 example/ohos 编译报找不到插件注册文件 | 该文件由 Flutter 工具根据 pubspec.yaml 的 ohos 配置自动生成。解法:先 flutter pub get 再构建 |
oh-package.json5 模板占位符 | 元信息为 “Please describe the basic information.” | 模板默认占位符。解法:替换为真实描述与作者信息(commit 884f0a8) |
| 孤儿 MainActivity.kt | example/android 下出现包名与 gradle namespace 不匹配、未被清单引用的 MainActivity.kt | 误生成文件。解法:核对 build.gradle.kts namespace 后删除孤儿文件(commit 18f1706) |
已知问题
- 鸿蒙端无法真实发送短信 —
ohos.permission.SEND_MESSAGES为 system_basic 级别权限,第三方(normal APL)应用无法申请,系统也未向第三方开放短信发送 API。插件按受限语义返回smsUnavailable错误。 - SIM 卡信息不可读 — HarmonyOS 未向第三方开放订阅(SIM 卡)信息读取 API,
getSimCards()恒返回空列表。 - 状态回执事件不可用 — 无第三方短信回执机制,
statusEvents恒为空流(保持打开但不产生事件)。
未来优化
- 拉起系统短信编辑器 — 在鸿蒙端扩展一个新方法,通过
Want/Intent拉起系统短信编辑页(预填收件人与内容),由用户在系统短信应用内完成发送,作为受限语义的可用替代方案; - 系统应用签名支持 — 若目标设备允许应用以 system_basic 及以上 APL 签名(如行业定制终端),可将受限分支替换为基于
@ohos.telephony.sms的真实实现,Dart 契约不变; - example 增强 — 在能力不可用时展示"使用系统短信"引导按钮,提升示例完整度。
九、总结
将一个 Flutter 三方库适配到 OHOS 平台,核心路径可以概括为 三步走:
1. 找对应 ── 找到 OHOS 对每个 Android 原生 API 的等价实现(或确认无等价物)
2. 保契约 ── 确保方法通道名、方法名、返回值结构完全一致(channel / method / map)
3. 补缺口 ── 对于 OHOS 不提供的 API,用合理方案弥补(受限语义、能力检测、UI 引导)
对于 sms_sender_plus 三方库,适配涉及 ohos/ 插件实现(index.ets、SmsSenderPlusPlugin.ets、HAR 配置)、example/ohos 示例工程、两份 README.OpenHarmony 文档与 pubspec.yaml 的 ohos 平台注册。Dart 层和其他平台的代码完全不受影响——这正是 Flutter 跨平台三方库生态的魅力所在。
本次适配的核心经验:当目标平台对某类能力有硬性系统限制时(如鸿蒙短信权限为 system_basic),不要硬造无效调用,而是给出确定性的"受限语义",并用能力检测接口(isSmsAvailable())让上层 UI 与业务逻辑做出正确决策。接口签名对齐 + 语义自洽 + 文档透明,就是一次合格的平台适配。
参考文档
更多推荐

所有评论(0)