1. 为什么选择Flutter+OpenHarmony开发SIM卡管理工具
在移动互联网时代,双卡双待已成为智能手机的标配功能,但原生Android和iOS系统对多SIM卡的管理功能往往较为基础。作为一名长期关注移动开发的工程师,我发现通过Flutter框架结合OpenHarmony系统能力,可以构建出功能更完善、体验更统一的SIM卡管理解决方案。
Flutter的跨平台特性让我们可以用一套代码同时覆盖Android和OpenHarmony设备,而OpenHarmony提供的分布式能力则为SIM卡管理带来了新的可能性。比如,我们可以实现:
- 跨设备查看SIM卡状态(如智能手表查看手机SIM卡信息)
- 统一管理家庭多台设备的移动数据使用情况
- 基于场景自动切换主副卡(如到家自动切换为家庭套餐卡)
从技术实现角度看,OpenHarmony的Telephony子系统提供了完整的SIM卡管理API,包括:
dart复制// 获取SIM卡基本信息示例
List<SimInfo> simInfos = await Telephony.getSimInfo();
simInfos.forEach((sim) {
print('卡槽${sim.slotIndex}: ${sim.carrierName}');
});
而Flutter的插件机制可以完美桥接这些原生能力,同时保持UI层的高度一致性。这种组合既发挥了OpenHarmony的系统级能力,又保留了Flutter的开发效率优势。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开发环境搭建与项目初始化
2.1 Flutter for OpenHarmony环境配置
首先需要搭建支持OpenHarmony的Flutter开发环境。与标准Flutter环境不同,我们需要安装openharmony_flutter分支:
bash复制git clone -b openharmony https://gitee.com/openharmony-sig/flutter_flutter.git
export PATH="$PATH:`pwd`/flutter_flutter/bin"
flutter doctor
关键依赖包括:
- OpenHarmony SDK 3.2+
- DevEco Studio 3.1+
- Node.js 16.x
- Java JDK 11
注意:目前Flutter for OpenHarmony仍在快速迭代中,建议锁定特定版本以避免兼容性问题。我在实际使用中发现flutter_oh_3.2.5分支最为稳定。
2.2 创建Flutter-OpenHarmony混合工程
使用DevEco Studio创建Native工程后,通过flutter create集成Flutter模块:
bash复制flutter create --template=module --org=com.example sim_manager
关键配置文件修改:
entry/build.gradle添加Flutter依赖oh-package.json5配置Flutter插件resources/base/profile/main_pages.json注册Flutter页面
3. SIM卡核心功能实现
3.1 获取SIM卡基本信息
通过OpenHarmony的telephony子系统获取SIM卡数据:
dart复制import 'package:ohos_telephony/ohos_telephony.dart';
Future<List<SimCard>> getSimCards() async {
final telephony = Telephony();
List<SimCard> cards = [];
try {
final simInfos = await telephony.getSimInfo();
for (var info in simInfos) {
cards.add(SimCard(
slotIndex: info.slotIndex,
imei: await telephony.getImei(info.slotIndex),
carrierName: info.carrierName ?? '未知运营商',
signalLevel: await telephony.getSignalLevel(info.slotIndex),
isDataEnabled: await telephony.isDataEnabled(info.slotIndex)
));
}
} on PlatformException catch (e) {
debugPrint('获取SIM卡信息失败: ${e.message}');
}
return cards;
}
3.2 移动数据开关控制
实现双卡数据切换的核心逻辑:
dart复制Future<bool> switchDataSim(int slotIndex) async {
final telephony = Telephony();
try {
// 先禁用所有卡的数据
final simInfos = await telephony.getSimInfo();
for (var info in simInfos) {
if (await telephony.isDataEnabled(info.slotIndex)) {
await telephony.setDataEnabled(info.slotIndex, false);
}
}
// 启用目标卡数据
return await telephony.setDataEnabled(slotIndex, true);
} on PlatformException catch (e) {
debugPrint('切换数据卡失败: ${e.message}');
return false;
}
}
3.3 流量使用监控
结合OpenHarmony的NetworkManager统计各SIM卡流量:
dart复制class TrafficMonitor {
final NetworkManager _network = NetworkManager();
Map<int, TrafficStats> _stats = {};
Future<void> startMonitoring() async {
Timer.periodic(Duration(minutes: 5), (_) async {
final simInfos = await Telephony().getSimInfo();
for (var info in simInfos) {
final stats = await _network.getTrafficStats(info.slotIndex);
_stats[info.slotIndex] = stats;
_checkQuota(info.slotIndex, stats);
}
});
}
void _checkQuota(int slot, TrafficStats stats) {
final used = stats.totalBytes / 1024 / 1024;
if (used > _quota[slot]!) {
_showNotification('卡槽$slot 流量已超限');
}
}
}
4. 典型问题排查与优化
4.1 权限申请处理
OpenHarmony的权限系统与Android有所不同,需要在config.json中声明:
json复制{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.GET_TELEPHONY_STATE"
},
{
"name": "ohos.permission.SET_TELEPHONY_STATE"
},
{
"name": "ohos.permission.GET_NETWORK_INFO"
}
]
}
}
动态权限申请示例:
dart复制Future<bool> _checkPermission() async {
final result = await PermissionHandler()
.requestPermissions([PermissionConstants.PERMISSION_GET_TELEPHONY_STATE]);
return result[PermissionConstants.PERMISSION_GET_TELEPHONY_STATE] ==
PermissionStatus.granted;
}
4.2 双卡设备兼容性问题
不同厂商的双卡实现存在差异,需要特殊处理:
dart复制Future<int> getDefaultDataSim() async {
try {
final simInfos = await Telephony().getSimInfo();
for (var info in simInfos) {
if (await Telephony().isDataEnabled(info.slotIndex)) {
return info.slotIndex;
}
}
return simInfos.first.slotIndex; // 默认返回第一张卡
} catch (e) {
// 部分设备getSimInfo可能返回空列表
return 0;
}
}
4.3 后台服务保活
OpenHarmony的后台机制要求配置持续任务:
- 在
config.json中添加:
json复制"backgroundModes": ["dataTransfer"]
- 创建Service并实现IBackgroundTask接口:
java复制public class DataMonitorService extends Ability implements IBackgroundTask {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
BackgroundTaskManager.getInstance().registerBackgroundTask(this);
}
@Override
public void doBackground() {
// 执行定时监控任务
}
}
5. 界面设计与用户体验优化
5.1 卡片式SIM信息展示
使用Flutter的CustomScrollView实现动态布局:
dart复制SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
final sim = simCards[index];
return Card(
child: Column(
children: [
ListTile(
leading: Icon(_getSimIcon(sim.slotIndex)),
title: Text(sim.carrierName),
subtitle: Text('信号强度: ${sim.signalLevel}/5'),
),
LinearProgressIndicator(
value: sim.usedData / sim.dataLimit,
),
SwitchListTile(
title: Text('移动数据'),
value: sim.isDataEnabled,
onChanged: (v) => _toggleData(sim.slotIndex, v),
)
],
),
);
},
childCount: simCards.length,
),
)
5.2 流量使用可视化
使用fl_chart实现流量统计图表:
dart复制LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
spots: _buildDailySpots(),
colors: [Colors.blue],
barWidth: 4,
isCurved: true,
),
],
titlesData: FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: _buildDayTitles(),
),
),
),
)
5.3 跨设备同步实现
利用OpenHarmony的分布式能力:
dart复制// 发布数据变更
DistributedDataManager.publish(
key: 'sim_status',
value: jsonEncode({
'activeSim': activeSlot,
'lastUpdate': DateTime.now().millisecondsSinceEpoch
})
);
// 订阅数据变更
DistributedDataManager.subscribe(
key: 'sim_status',
onChange: (value) {
final data = jsonDecode(value);
setState(() {
activeSlot = data['activeSim'];
});
}
);
6. 项目构建与发布
6.1 多模式构建配置
在flutter_oh/build.gradle中配置不同环境:
groovy复制flutterOh {
buildTypes {
debug {
ohosBuildType = "debug"
extraBuildConfig = [
enableDebug: true,
apiUrl: "http://test.api.example.com"
]
}
release {
ohosBuildType = "release"
extraBuildConfig = [
enableDebug: false,
apiUrl: "http://api.example.com"
]
}
}
}
6.2 鸿蒙应用签名
- 生成密钥库:
bash复制keytool -genkeypair -alias "simmanager" -keyalg RSA -keysize 2048 \
-validity 3650 -keystore simmanager.p12
- 在DevEco Studio中配置签名:
- File > Project Structure > Signing Configs
- 添加生成的.p12文件
- 配置自动签名
6.3 上架AppGallery准备
-
准备应用元数据:
- 多语言描述
- 屏幕截图(需包含OpenHarmony设备截图)
- 隐私政策声明
-
构建HAP包:
bash复制flutter build ohos --release
- 通过AppGallery Connect提交审核
7. 实际开发中的经验分享
在开发过程中,有几个关键点值得特别注意:
- SIM卡状态监听:OpenHarmony的SIM卡状态变更通知需要通过订阅CommonEvent实现:
dart复制final receiver = CommonEventReceiver(
events: ["usual.event.SIM_STATE_CHANGED"],
onReceive: (event) => _refreshSimStatus()
);
CommonEventManager.subscribe(receiver);
- 信号强度更新频率:实测发现不同设备信号强度更新频率差异很大,建议:
- 华为设备:每30秒请求一次
- 荣耀设备:每2分钟请求一次
- 其他设备:折中采用1分钟间隔
- 双卡切换延迟处理:部分设备切换数据卡后需要5-10秒才能生效,建议:
dart复制Future<void> _switchWithDelay(int slot) async {
await switchDataSim(slot);
await Future.delayed(Duration(seconds: 8));
if (!await _isDataEnabled(slot)) {
_showRetryDialog();
}
}
- 国际化注意事项:运营商名称需要做本地化处理:
dart复制String _getCarrierName(String rawName) {
switch(rawName) {
case 'China Mobile': return Localization.of(context).chinaMobile;
case 'China Unicom': return Localization.of(context).chinaUnicom;
default: return rawName;
}
}
- 测试策略建议:
- 优先在HiSilicon麒麟芯片设备测试(兼容性最好)
- 准备不同运营商的测试SIM卡(移动/联通/电信)
- 测试4G/5G网络切换场景
- 验证飞行模式切换后的状态恢复
这个项目最让我意外的是OpenHarmony的分布式能力给SIM卡管理带来的新可能。比如我们可以实现:
- 在平板上直接管理手机SIM卡
- 根据智能手表的位置自动切换手机数据卡
- 家庭多设备共享流量池监控
这些特性在传统Android生态中很难完美实现,而OpenHarmony+Flutter的组合为我们打开了新的大门。
