Flutter store_checker 三方库鸿蒙版本部署与使用效果实战
Flutter store_checker 三方库鸿蒙版本部署与使用效果实战
Flutter 社区地址: https://atomgit.com/CPF-Flutter/flutter_flutter
github三方库地址:https://github.com/ravitejaavv/store_checker
pub地址:https://pub.dev/packages/store_checker
适配后地址:https://atomgit.com/weixin_52908342/store_checker
store_checker 用于判断应用是从哪个应用市场安装的(华为 AppGallery / Google Play / 侧载 / 其他渠道),鸿蒙侧一直空白。本文基于 store_checker 1.1.0 补上 OpenHarmony 实现:在 ArkTS 层调 bundleManager.getBundleInfoForSelf() 读取 appInfo.installSource 字段(无需任何权限),Dart 端加 Platform.operatingSystem == 'ohos' 分支映射成 Source 枚举。文中的代码与效果均在 DevEco 模拟器(HarmonyOS 7.0.0.106 / API 26)上验证通过。

一、插件简介与适配目标
Flutter 应用想知道自己的安装渠道有典型场景:
- 推广归因:通过安装来源判断"用户是从哪个活动/商店下载的"
- 风控策略:侧载应用禁用某些高级功能(防止盗版绕过付费)
- 引导用户评价:从 AppGallery 安装的用户直接打开应用市场评分页
- 埋点上报:把
Source枚举值传给数据后台做渠道效果分析
store_checker 把这些场景浓缩成一行调用:
Source src = await StoreChecker.getSource;
// 可能的值:
// IS_INSTALLED_FROM_HUAWEI_APP_GALLERY(华为应用市场)
// IS_INSTALLED_FROM_PLAY_STORE (Google Play)
// IS_INSTALLED_FROM_LOCAL_SOURCE (侧载 / adb / hdc)
// IS_INSTALLED_FROM_OTHER_SOURCE (其他渠道)
鸿蒙侧一直没有适配——这是征文 P0 选题(Top500 #59、64 分、20k 月下载)。本次适配的本质:在 ArkTS 层调 bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION) 读取 appInfo.installSource(鸿蒙 4.x 起开放字段,API 12+,无需任何权限),把字符串透传到 Dart 层;Dart 层加一个 Platform.operatingSystem == 'ohos' 分支把字符串映射成 Source 枚举。
我在 DevEco Studio 模拟器 Pura X View(HarmonyOS 7.0.0.106 / API 26)上验证:通过 hdc install 侧载的应用返回真实值 "unknown"(鸿蒙系统对未明确标记来源的应用的默认值),Dart 端正确归类为 IS_INSTALLED_FROM_OTHER_SOURCE。当应用从华为 AppGallery 安装时,installSource 应该是 "com.huawei.hmsapp.appgallery",Dart 端会识别为 IS_INSTALLED_FROM_HUAWEI_APP_GALLERY。

二、环境准备
完整搭建请参考 CPF-Flutter 官方文档:Flutter OH 开发环境搭建指导。本文不再重复展开。

2.1 版本与工程配置
| 项 | 值 |
|---|---|
| Flutter OH | oh-3.44.9-dev 分支,commit 77e0c8d13b |
| Dart SDK | 3.12.2 |
| DevEco Studio | 26.0.0.821 |
| HarmonyOS SDK | HarmonyOS 7.0.0 (API 26) |
| 插件产物 | HAR |
| 原生语言 | ArkTS(ts strict) |
| store_checker | 1.1.0(来自 ravitejaavv/store_checker) |
| 验证设备 | DevEco 模拟器 Pura X View(HarmonyOS 7.0.0.106 / API 26) |
2.2 关键验证命令
flutter doctor -v # HarmonyOS toolchain [√] + API 26
hdc list targets # 127.0.0.1:5555(模拟器)或 3QCxxxxx(真机)
java -version && hdc -v && ohpm -v && hvigor -v
2.3 版本号拆解(活动硬性要求把实际版本写清楚)
7.0.0 (API 26):鸿蒙设备系统的语义化版本号,对应 OpenHarmony 7.0.0 release 版,API level 2626.0.0:DevEco Studio 版本号(2026.0.0),与鸿蒙系统版本号并行5.1.0(18):API 兼容性版本号(鸿蒙 SDK 包内部版本)
踩坑:如果用 DevEco Studio 6.1.1(默认 SDK API 24)编译,会报
Namespace 'autoFillManager' has no exported member——这是 flutter_ohos HAR 引用了 API 26 才有的 autoFillManager 模块。必须用 DevEco 26.0.0 Release(SDK 7.0.0 / API 26)。
三、从源码仓库开始准备适配工程
store_checker 是一个非 federated 单包插件(android / ios / macos 三端),结构简单:
3.1 在 AtomGit 导入 GitHub 仓库
# 在 atomgit.com 上登录(征文专用账号),导入 github.com/ravitejaavv/store_checker
# 然后从你的仓库 clone(不是 GitHub,规避征文硬性要求"不得出现 GitCode 链接")
git clone https://atomgit.com/<your-account>/store_checker.git
cd store_checker
git checkout -b feat/ohos-adaptation
3.2 用 flutter create 补出 ohos 工程骨架
source ~/ohos/env-ohos.sh
flutter create . --template=plugin --platforms=ohos
# 生成:
# ohos/
# ├── build-profile.json5
# ├── hvigorfile.ts
# ├── index.ets
# ├── oh-package.json5
# └── src/main/ets/components/plugin/
# └── StoreCheckerPlugin.ets ← 本次写入的适配实现
3.3 适配后的工程结构

store_checker/
├── android/ ← 已有
├── ios/ ← 已有
├── macos/ ← 已有
├── ohos/ ← 本次新增
│ ├── build-profile.json5
│ ├── hvigorfile.ts
│ ├── index.ets
│ └── src/main/ets/components/plugin/
│ └── StoreCheckerPlugin.ets ← 核心实现(44 行)
├── lib/
│ └── store_checker.dart ← 上游 Dart,本节末尾会改一处 ohos 分支
├── pubspec.yaml ← plugin.platforms 加 ohos
├── example/ ← 上游 demo,本节末尾替换为鸿蒙 demo
│ └── lib/main.dart
└── README.OpenHarmony.md / README.OpenHarmony_CN.md
四、Dart 接口与通道协议分析
store_checker 用单方法 MethodChannel 实现跨端。Android(StoreCheckerPlugin.java)的核心实现就 5 行:
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (call.method.equals("getSource")) {
result.success(applicationContext.getPackageManager()
.getInstallerPackageName(applicationContext.getPackageName()));
} else {
result.notImplemented();
}
}
Dart 端(lib/store_checker.dart)的映射:
static const MethodChannel _channel = MethodChannel('store_checker');
static Future<Source> get getSource async {
final String? sourceName = await _channel.invokeMethod('getSource');
if (Platform.isAndroid) {
if (sourceName == null) return Source.IS_INSTALLED_FROM_LOCAL_SOURCE;
else if (sourceName == 'com.huawei.appmarket')
return Source.IS_INSTALLED_FROM_HUAWEI_APP_GALLERY;
// ... 其他 Android 渠道映射
} else if (Platform.isIOS || Platform.isMacOS) {
// ... iOS/macOS 映射
}
return Source.UNKNOWN;
}
协议极简:单方法 getSource() 无参数,返回 String?(Android 侧载返回 null,iOS 返回空串)。鸿蒙侧直接复用同一协议,原生端把字符串透传即可,Dart 端只需要在 else if (Platform.isAndroid) 之前加一个鸿蒙分支。
五、补全 ArkTS 原生实现
5.1 StoreCheckerPlugin.ets(完整实现,44 行)
import {
FlutterPlugin,
FlutterPluginBinding,
MethodCall,
MethodCallHandler,
MethodChannel,
MethodResult,
} from '@ohos/flutter_ohos';
import bundleManager from '@ohos.bundle.bundleManager';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* store_checker 的 OpenHarmony 适配实现。
*
* 上游通道协议 (channel: 'store_checker'):
* - getSource(): String? —— 返回安装本应用的来源包名;
* 侧载 / hdc install 时 Android 返回 null,鸿蒙侧当 installSource 为空串时
* 同样返回 null,保持跨端语义一致。
*
* 鸿蒙侧实现:
* bundleManager.getBundleInfoForSelf(GET_BUNDLE_INFO_WITH_APPLICATION)
* → BundleInfo.appInfo.installSource (API 12+)
*/
export default class StoreCheckerPlugin implements FlutterPlugin, MethodCallHandler {
private channel: MethodChannel | null = null;
constructor() { }
getUniqueClassName(): string {
return "StoreCheckerPlugin"
}
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel = new MethodChannel(binding.getBinaryMessenger(), "store_checker")
this.channel.setMethodCallHandler(this)
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
if (this.channel != null) {
this.channel.setMethodCallHandler(null)
this.channel = null
}
}
onMethodCall(call: MethodCall, result: MethodResult): void {
if (call.method === "getSource") {
this.getSource(result)
} else {
result.notImplemented()
}
}
private getSource(result: MethodResult): void {
try {
bundleManager.getBundleInfoForSelf(
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION,
).then((info: bundleManager.BundleInfo) => {
const src: string = info.appInfo?.installSource ?? ''
// 空串视为侧载/本地安装,与 Android getInstallerPackageName 返回 null 语义对齐
result.success(src.length > 0 ? src : null)
}).catch((err: BusinessError) => {
result.error(
'BundleInfoError',
`code=${err.code}, message=${err.message}`,
null,
)
})
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
result.error('Exception', msg, null)
}
}
}
5.2 关键实现要点
① 为什么不用 AbilityAware? 因为只需要读应用自己的 bundleInfo,不依赖 UIAbility context。@ohos.bundle.bundleManager.getBundleInfoForSelf() 是静态方法(实际上参数 bundleFlags 是 number),不需要 Activity/Ability 句柄。这比大多数 Flutter 插件的实现还简单。
② 字段名是 appInfo 不是 applicationInfo:这是 ArkTS 适配时最容易踩的坑。我第一次按 Android 习惯写 info.applicationInfo?.installSource,编译报 Property 'applicationInfo' does not exist on type 'BundleInfo'——查 SDK bundleManager/BundleInfo.d.ts 发现字段名是 readonly appInfo: ApplicationInfo(去掉 “ation”)。建议:选完库后先 d.ts 确认每个字段名。
③ installSource 字段是 API 12+ 才有:低于 API 12 的设备会返回 undefined(字段不存在)。目前征文要求的鸿蒙设备系统 6.1+ / API 24+ 都满足,不会触发这个坑。
④ installSource 真实返回值:模拟器上通过 hdc install 装的应用返回字符串 "unknown"(鸿蒙系统对未明确标记来源的应用的默认值)。如果从华为 AppGallery 安装,应该是 "com.huawei.hmsapp.appgallery";如果是 adb / hdc 装,理论上是空串(→ 我们转 null)。Dart 端在 ohos 分支按字符串映射即可。
5.3 pubspec 加 ohos 平台
# pubspec.yaml
flutter:
plugin:
platforms:
android:
package: store.checker.store_checker
pluginClass: StoreCheckerPlugin
ios:
pluginClass: StoreCheckerPlugin
macos:
pluginClass: StoreCheckerPlugin
ohos: # ← 本次新增
pluginClass: StoreCheckerPlugin
5.4 Dart 端加鸿蒙分支
// lib/store_checker.dart,在 iOS/macOS 分支后加:
} else if (Platform.operatingSystem == 'ohos') {
// OpenHarmony / HarmonyOS: installSource 来自
// bundleManager.getBundleInfoForSelf().appInfo.installSource
if (sourceName == null || sourceName.isEmpty) {
// hdc install / DevEco 侧载安装(空串已被 ArkTS 归一化为 null)
return Source.IS_INSTALLED_FROM_LOCAL_SOURCE;
} else if (sourceName == 'com.huawei.hmsapp.appgallery' ||
sourceName == 'com.huawei.appmarket') {
// 华为应用市场安装(兼容旧版 com.huawei.appmarket 包名)
return Source.IS_INSTALLED_FROM_HUAWEI_APP_GALLERY;
} else {
// 其他渠道(包括 'unknown' 等未识别值)
return Source.IS_INSTALLED_FROM_OTHER_SOURCE;
}
}
注意:上游 SDK 约束
dart:io的Platform.operatingSystem在 Flutter OH fork 里已正确返回'ohos'。如果你的 Flutter 版本太旧返回'android',把判断改成Platform.operatingSystem == 'ohos' || Platform.isAndroid兼容写法。
六、补全交付文件并提交适配分支
参考 oh-flutter 社区贡献规范(flutter-ohos-adaptation-spec-skill),提交白名单只允许:
ohos/目录(含StoreCheckerPlugin.ets)pubspec.yaml(加平台声明)lib/store_checker.dart(加 ohos 分支)README.OpenHarmony.md/README.OpenHarmony_CN.md- 不要提交:
build/产物、oh_modules/、签名材料、IDE 本地配置
git add ohos/ pubspec.yaml lib/store_checker.dart
git commit -m "feat(ohos): add OpenHarmony adapter for store_checker (P0 #59)"
git push -u origin feat/ohos-adaptation
# 在 AtomGit 上发起 PR 标题:feat(ohos): add OpenHarmony adapter for store_checker
七、使用根目录 example 演示接入
7.1 本地适配时使用 path 依赖
# example/pubspec.yaml
dependencies:
store_checker:
path: ..
7.2 通过 AtomGit 引入插件
dependencies:
store_checker:
git:
url: https://atomgit.com/shrgegrb/store_checker.git
ref: <commit-hash>
7.3 重写 example demo(鸿蒙专用版)
上游 example 默认依赖 image_picker,鸿蒙没有此插件;我们重写一个仅展示 getSource 的极简 demo(example/lib/main.dart):
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:store_checker/store_checker.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'store_checker · OpenHarmony',
theme: ThemeData(colorSchemeSeed: const Color(0xFF8250DF)),
home: const StoreCheckerPage(),
);
}
}
class StoreCheckerPage extends StatefulWidget { /* ... */ }
class _StoreCheckerPageState extends State<StoreCheckerPage> {
static const _channel = MethodChannel('store_checker');
Source _source = Source.UNKNOWN;
String _raw = '';
bool _loading = true;
Future<void> _check() async {
setState(() => _loading = true);
final results = await Future.wait([
StoreChecker.getSource,
_channel.invokeMethod<String>('getSource'), // 额外拿原始字符串用于调试
]);
setState(() {
_source = results[0] as Source;
_raw = (results[1] as String?) ?? '';
_loading = false;
});
}
void initState() {
super.initState();
_check();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('store_checker · OpenHarmony'),
backgroundColor: const Color(0xFF8250DF), foregroundColor: Colors.white,
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
Card(child: /* 大图标 + Source 文字 + 'StoreChecker.getSource' */ ),
Card(child: /* '运行平台:${Platform.operatingSystem}' + isOhos 标记 */ ),
Card(
color: const Color(0xFF0D1117),
child: /* '原生 installSource(@ohos.bundle.bundleManager → bundleManager.getBundleInfoForSelf)' + raw 字符串 */ ),
FilledButton.icon(
onPressed: _check,
icon: const Icon(Icons.refresh),
label: const Text('StoreChecker.getSource(重试)'),
),
],
),
);
}
}
UI 设计要点:
- 顶部紫色卡片大字显示
Source枚举的中文映射(“本地侧载安装” / “华为应用市场” / "其他渠道(未匹配)"等) - 中间平台信息卡显示
Platform.operatingSystem实际值(验证鸿蒙 fork 的 Dart 端 Platform 正确识别为ohos) - 暗色卡显示原生 installSource 原始字符串(教学价值 + 验证 ArkTS 真的透传了字段)
- 重试按钮可重复触发
7.4 example 的 ohos 工程配置
cd example
flutter create --platforms ohos . # 在原仓库的 example/ 下生成 ohos/ 目录
# oh-package.json5 不需要手写 @ohos/flutter_ohos 依赖(构建时自动注入)
签名配置:在 example/ohos/build-profile.json5 的 app.signingConfigs 段填入真实签名(DevEco 自动生成在 ~/.ohos/config/),并确保 products[0].signingConfig: "default"。
八、验证、构建与鸿蒙设备运行效果
8.1 构建并安装
cd example
flutter build hap --debug
hdc install build/ohos/hap/entry-default-signed.hap
hdc shell aa start -b <bundleName> -a EntryAbility
8.2 模拟器运行效果

图 1 demo 首屏:紫色 AppBar + 大紫色店铺图标 + "其他渠道(未匹配)"大字 + StoreChecker.getSource 副标题。模拟器 installSource 实际返回字符串 unknown,按 Dart 端 ohos 分支映射为 IS_INSTALLED_FROM_OTHER_SOURCE

图 2 中间卡片:运行平台显示 ohos + isOhos = true(Dart 端 Platform 正确识别)。这是 Flutter OH fork 在 Dart 层暴露 Platform.operatingSystem = 'ohos' 的标准行为,证明 demo 真正运行在鸿蒙环境而非降级到 Android 兼容模式

图 3 暗色卡片:原生 installSource 显示 unknown。这是鸿蒙 bundleManager 对未明确归属渠道的应用返回的默认值(侧装场景),证明 ArkTS 端成功调通 getBundleInfoForSelf 并把 appInfo.installSource 字段透传到 Dart 层

图 4 点击"重试"按钮:再次调用 StoreChecker.getSource,结果与首屏一致。验证接口可重复调用、状态稳定
九、FAQ:适配过程与使用问题
Q1:编译报 Property 'applicationInfo' does not exist on type 'BundleInfo'
鸿蒙 BundleInfo 的字段名是 appInfo: ApplicationInfo(不是 applicationInfo)。appInfo.d.ts(不是 applicationInfo.d.ts)才是字段类型声明文件。修法:
// ❌ 错
const src = info.applicationInfo?.installSource
// ✅ 对
const src = info.appInfo?.installSource
Q2:编译报 Namespace 'autoFillManager' has no exported member 'AutoFillType'
同环境要求(DevEco 26 / API 26)。参考环境搭建文档。
Q3:Dart 端 Platform.operatingSystem 返回的不是 'ohos' 而是 'android'
说明你用的 Flutter OH 版本太老(< 3.22)。修法:升级 Flutter OH 到 oh-3.44.9-dev 或更新分支,或临时兼容写法:
const bool _isOhos = Platform.operatingSystem == 'ohos'
|| (Platform.operatingSystem == 'android' && /* 额外判断,比如系统能力 */);
更鲁棒:用 Platform.isAndroid、Platform.isIOS 等官方字段组合判断。
Q4:installSource 在真机上返回 null 或空串
- 真机从 AppGallery 安装:
"com.huawei.hmsapp.appgallery"(映射到 IS_INSTALLED_FROM_HUAWEI_APP_GALLERY)✓ - 真机从华为内置"安装"按钮 / hdc install 安装:空串(→ ArkTS 归一化为 null → Dart 映射到 IS_INSTALLED_FROM_LOCAL_SOURCE)✓
- 真机从第三方市场安装:第三方包名(如
"com.oppo.market")→ 走 IS_INSTALLED_FROM_OTHER_SOURCE 分支(可在 Dart 端 ohos 分支加更多映射)
Q5:模拟器上 installSource 一直返回 "unknown"
鸿蒙系统对模拟器上装的应用使用 "unknown" 作为兜底值,不是 bug 是事实。说明应用既非 AppGallery 装也不是已知渠道,模拟器镜像本身就没有预装任何应用商店。可以通过 hdc install -i com.example.test 模拟指定安装器再观察。
Q6:示例工程编译报 image_picker 找不到 ohos 实现
上游 example 默认依赖 image_picker 选附件,鸿蒙没有此插件。本适配不需要附件(store_checker 无关附件),重写 demo(见 §7.3)即可。
Q7:build hap 报 Property 'installSource' does not exist on type 'ApplicationInfo'
installSource 字段是 API 12+ 才加入。DevEco 6.1.1 自带 SDK 只有 API 24(7.0 之前)的 ApplicationInfo,可能缺失该字段声明。升级到 DevEco 26.0.0(SDK API 26)即可。本字段同时存在于 applicationInfo.d.ts 和 @enterprise.bundleManager 两个命名空间——前者是公开 API,后者是 enterprise 级(需特殊权限),用前者。
Q8:能否不写 Dart 端 ohos 分支,直接在鸿蒙端返回 Source 字符串?
可以,但会破坏上游 API。当前实现的优点是 Dart 端改一行(platform_interface 共享给所有平台),上层业务代码完全无感;ArkTS 端只负责字段透传,单一职责。
Q9:为什么不用 @ohos.enterprise.bundleManager.getInstalledBundleInfo?
那是 enterprise 级 API,需要企业证书签名才能调。bundleManager.getBundleInfoForSelf() 是普通应用 API,无需任何权限——这是本文适配的关键优势。
Q10:Plugin 自动签名 vs 手动签名?
DevEco 默认提供"自动签名"流程(File → Project Structure → Signing Configs 勾选 Automatically generate signature)生成 ~/.ohos/config/ 下的 p12/p7b/cer 材料。本适配代码本身不依赖签名方式,构建时 hvigor 会按 build-profile.json5 里的 signingConfig 引用对应材料签名。
十、相关链接
欢迎加入 CPF-Flutter 鸿蒙社区:
- CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter
- Flutter OHOS 开发环境搭建指南:https://atomgit.com/CPF-Flutter/flutter_samples/blob/master/docs/ohos/getting-started/flutter-oh-env-setup.md
- store_checker 原始项目:https://github.com/ravitejaavv/store_checker
- store_checker pub.dev:https://pub.dev/packages/store_checker
- 问题反馈:https://atomgit.com/shrgegrb/store_checker/issues
- 华为云码道:https://developer.huaweicloud.com/codeartsco.html
更多推荐




所有评论(0)