
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
🎯 欢迎来到 Flutter for OpenHarmony 社区!本文将深入讲解 Flutter 中 package_info_plus 应用信息获取组件的使用方法,带你全面掌握在应用中获取版本号、包名等应用元数据的各种技巧。
一、package_info_plus 组件概述
在 Flutter for OpenHarmony 应用开发中,package_info_plus 是一个非常实用的应用信息获取插件,它允许开发者获取当前应用的各种元数据信息,如版本号、构建号、包名、应用名称等。这些信息在版本管理、更新检测、用户反馈、统计分析等场景中非常重要。
📋 package_info_plus 组件特点
| 特点 | 说明 |
|---|---|
| 跨平台支持 | 支持 Android、iOS、Web、Windows、macOS、Linux、OpenHarmony |
| 信息丰富 | 提供版本号、构建号、包名、应用名称等多种信息 |
| 简单易用 | API 简洁直观,一行代码即可获取信息 |
| 无需权限 | 不需要任何特殊权限即可使用 |
| 实时获取 | 运行时动态获取应用信息 |
💡 使用场景:版本检查、应用更新、关于页面、用户反馈、统计分析、日志记录等。
二、OpenHarmony 平台适配说明
2.1 兼容性信息
本项目基于 package_info_plus@8.1.0 开发,适配 Flutter 3.27.5-ohos-1.0.4。
2.2 支持的功能
在 OpenHarmony 平台上,package_info_plus 支持以下功能:
| 功能 | 说明 | OpenHarmony 支持 |
|---|---|---|
| 应用名称 | 获取应用显示名称 | ✅ yes |
| 包名 | 获取应用包标识 | ✅ yes |
| 版本号 | 获取应用版本号 | ✅ yes |
| 构建号 | 获取应用构建号 | ✅ yes |
| 应用签名 | 获取应用签名信息 | ✅ yes |
三、项目配置与安装
3.1 添加依赖配置
首先,需要在你的 Flutter 项目的 pubspec.yaml 文件中添加 package_info_plus 依赖。
打开项目根目录下的 pubspec.yaml 文件,找到 dependencies 部分,添加以下配置:
yaml
dependencies:
flutter:
sdk: flutter
# 添加 package_info_plus 依赖(OpenHarmony 适配版本)
package_info_plus:
git:
url: "https://atomgit.com/openharmony-sig/flutter_plus_plugins.git"
path: "packages/package_info_plus/package_info_plus"
ref: "br_package_info_plus-v8.1.0_ohos"
配置说明:
- 使用 git 方式引用开源鸿蒙适配的 flutter_plus_plugins 仓库
url:指定 AtomGit 托管的仓库地址path:指定 package_info_plus 包的具体路径ref:指定适配 OpenHarmony 的分支版本- 本项目基于
package_info_plus@8.1.0开发,适配 Flutter 3.27.5-ohos-1.0.4
⚠️ 重要:对于 OpenHarmony 平台,必须使用 git 方式引用适配版本,不能直接使用 pub.dev 的版本号。
3.2 下载依赖
配置完成后,需要在项目根目录执行以下命令下载依赖:
bash
flutter pub get
执行成功后,你会看到类似以下的输出:
Running "flutter pub get" in my_cross_platform_app...
Resolving dependencies...
Got dependencies!
3.3 依赖自动配置说明
执行 flutter pub get 后,OpenHarmony 平台的依赖会自动配置到 ohos/entry/oh-package.json5 文件中。Flutter 构建系统会自动处理平台相关的依赖配置,无需手动干预。
四、package_info_plus 基础用法
4.1 导入库
在使用 package_info_plus 之前,需要先导入库:
dart
import 'package:package_info_plus/package_info_plus.dart';
4.2 获取应用信息
获取应用信息的基本方式:
dart
Future<PackageInfo> _getPackageInfo() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
return packageInfo;
}
4.3 获取各项信息
dart
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appName = packageInfo.appName; // 应用名称
String packageName = packageInfo.packageName; // 包名
String version = packageInfo.version; // 版本号
String buildNumber = packageInfo.buildNumber; // 构建号
String buildSignature = packageInfo.buildSignature; // 应用签名
4.4 在 Widget 中使用
dart
class AppInfoWidget extends StatefulWidget {
const AppInfoWidget({super.key});
@override
State<AppInfoWidget> createState() => _AppInfoWidgetState();
}
class _AppInfoWidgetState extends State<AppInfoWidget> {
PackageInfo? _packageInfo;
@override
void initState() {
super.initState();
_initPackageInfo();
}
Future<void> _initPackageInfo() async {
final info = await PackageInfo.fromPlatform();
setState(() {
_packageInfo = info;
});
}
@override
Widget build(BuildContext context) {
if (_packageInfo == null) {
return const CircularProgressIndicator();
}
return Column(
children: [
Text('应用名称: ${_packageInfo!.appName}'),
Text('版本号: ${_packageInfo!.version}'),
Text('构建号: ${_packageInfo!.buildNumber}'),
],
);
}
}
五、常用 API 详解
5.1 PackageInfo 类
PackageInfo 类包含以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| appName | String | 应用显示名称 |
| packageName | String | 应用包名 |
| version | String | 应用版本号 |
| buildNumber | String | 应用构建号 |
| buildSignature | String | 应用签名(仅 Android) |
| installerStore | String? | 安装来源商店 |
5.2 fromPlatform 方法
从平台获取应用信息:
dart
static Future<PackageInfo> fromPlatform()
返回值:
- 返回
PackageInfo对象,包含应用的各种信息
5.3 使用示例
dart
Future<void> printAppInfo() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
print('应用名称: ${packageInfo.appName}');
print('包名: ${packageInfo.packageName}');
print('版本号: ${packageInfo.version}');
print('构建号: ${packageInfo.buildNumber}');
print('签名: ${packageInfo.buildSignature}');
}
六、实际应用场景
6.1 关于页面
dart
class AboutPage extends StatefulWidget {
const AboutPage({super.key});
@override
State<AboutPage> createState() => _AboutPageState();
}
class _AboutPageState extends State<AboutPage> {
PackageInfo? _packageInfo;
@override
void initState() {
super.initState();
_loadPackageInfo();
}
Future<void> _loadPackageInfo() async {
final info = await PackageInfo.fromPlatform();
setState(() {
_packageInfo = info;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('关于')),
body: _packageInfo == null
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
children: [
const SizedBox(height: 20),
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(16),
),
child: const Icon(Icons.apps, size: 48, color: Colors.white),
),
const SizedBox(height: 16),
Text(
_packageInfo!.appName,
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'版本 ${_packageInfo!.version} (${_packageInfo!.buildNumber})',
style: const TextStyle(color: Colors.grey),
),
const SizedBox(height: 32),
_buildInfoTile('应用名称', _packageInfo!.appName),
_buildInfoTile('包名', _packageInfo!.packageName),
_buildInfoTile('版本号', _packageInfo!.version),
_buildInfoTile('构建号', _packageInfo!.buildNumber),
const SizedBox(height: 20),
const Text(
'© 2024 Flutter for OpenHarmony',
style: TextStyle(color: Colors.grey),
),
],
),
),
);
}
Widget _buildInfoTile(String label, String value) {
return Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(color: Colors.grey)),
Text(value, style: const TextStyle(fontWeight: FontWeight.w500)),
],
),
);
}
}
6.2 版本检查与更新
dart
class VersionCheckService {
static const String _latestVersion = '2.0.0';
static const String _updateUrl = 'https://example.com/download';
Future<Map<String, dynamic>> checkForUpdate() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String currentVersion = packageInfo.version;
bool hasUpdate = _compareVersions(_latestVersion, currentVersion) > 0;
return {
'hasUpdate': hasUpdate,
'currentVersion': currentVersion,
'latestVersion': _latestVersion,
'updateUrl': _updateUrl,
};
}
int _compareVersions(String v1, String v2) {
List<int> parts1 = v1.split('.').map(int.parse).toList();
List<int> parts2 = v2.split('.').map(int.parse).toList();
for (int i = 0; i < 3; i++) {
if (parts1[i] > parts2[i]) return 1;
if (parts1[i] < parts2[i]) return -1;
}
return 0;
}
}
6.3 用户反馈
dart
class FeedbackPage extends StatefulWidget {
const FeedbackPage({super.key});
@override
State<FeedbackPage> createState() => _FeedbackPageState();
}
class _FeedbackPageState extends State<FeedbackPage> {
PackageInfo? _packageInfo;
final TextEditingController _feedbackController = TextEditingController();
@override
void initState() {
super.initState();
_loadPackageInfo();
}
Future<void> _loadPackageInfo() async {
final info = await PackageInfo.fromPlatform();
setState(() {
_packageInfo = info;
});
}
Future<void> _submitFeedback() async {
String feedback = _feedbackController.text;
String deviceInfo = '''
应用版本: ${_packageInfo?.version ?? 'unknown'}
构建号: ${_packageInfo?.buildNumber ?? 'unknown'}
包名: ${_packageInfo?.packageName ?? 'unknown'}
反馈内容: $feedback
''';
// 提交反馈到服务器
debugPrint('提交反馈:\n$deviceInfo');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('感谢您的反馈!')),
);
Navigator.pop(context);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('意见反馈')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
const Icon(Icons.info_outline, size: 16, color: Colors.grey),
const SizedBox(width: 8),
Text(
'当前版本: ${_packageInfo?.version ?? "加载中..."}',
style: const TextStyle(color: Colors.grey),
),
],
),
),
const SizedBox(height: 16),
TextField(
controller: _feedbackController,
maxLines: 5,
decoration: const InputDecoration(
hintText: '请输入您的反馈意见...',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _submitFeedback,
child: const Text('提交反馈'),
),
),
],
),
),
);
}
}
6.4 日志记录
dart
class Logger {
static PackageInfo? _packageInfo;
static Future<void> init() async {
_packageInfo = await PackageInfo.fromPlatform();
}
static void log(String message, {String level = 'INFO'}) {
String timestamp = DateTime.now().toIso8601String();
String version = _packageInfo?.version ?? 'unknown';
String logMessage = '[$timestamp][$level][v$version] $message';
debugPrint(logMessage);
}
static void error(String message, [Object? error, StackTrace? stackTrace]) {
log('$message\nError: $error\nStackTrace: $stackTrace', level: 'ERROR');
}
}
// 使用示例
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Logger.init();
Logger.log('应用启动');
runApp(const MyApp());
}
6.5 设置页面
dart
class SettingsPage extends StatelessWidget {
const SettingsPage({super.key});
Future<PackageInfo> _getPackageInfo() async {
return await PackageInfo.fromPlatform();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('设置')),
body: FutureBuilder<PackageInfo>(
future: _getPackageInfo(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final packageInfo = snapshot.data!;
return ListView(
children: [
_buildSection('通用'),
_buildTile(Icons.info, '关于', () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const AboutPage()),
);
}),
_buildTile(Icons.update, '检查更新', () {
_checkUpdate(context, packageInfo.version);
}),
_buildTile(Icons.feedback, '意见反馈', () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const FeedbackPage()),
);
}),
_buildSection('版本信息'),
_buildInfoItem('当前版本', packageInfo.version),
_buildInfoItem('构建号', packageInfo.buildNumber),
_buildInfoItem('包名', packageInfo.packageName),
],
);
},
),
);
}
Widget _buildSection(String title) {
return Padding(
padding: const EdgeInsets.fromLTRB(16, 20, 16, 8),
child: Text(
title,
style: const TextStyle(
color: Colors.grey,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
);
}
Widget _buildTile(IconData icon, String title, VoidCallback onTap) {
return ListTile(
leading: Icon(icon),
title: Text(title),
trailing: const Icon(Icons.chevron_right),
onTap: onTap,
);
}
Widget _buildInfoItem(String label, String value) {
return ListTile(
title: Text(label),
subtitle: Text(value),
);
}
void _checkUpdate(BuildContext context, String currentVersion) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('当前已是最新版本 $currentVersion')),
);
}
}
七、完整示例代码
下面是一个完整的示例应用,展示了 package_info_plus 的各种用法:
dart
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PackageInfo Plus 示例',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF6366F1)),
useMaterial3: true,
),
home: const PackageInfoDemoPage(),
);
}
}
class PackageInfoDemoPage extends StatefulWidget {
const PackageInfoDemoPage({super.key});
@override
State<PackageInfoDemoPage> createState() => _PackageInfoDemoPageState();
}
class _PackageInfoDemoPageState extends State<PackageInfoDemoPage> {
PackageInfo? _packageInfo;
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadPackageInfo();
}
Future<void> _loadPackageInfo() async {
try {
final info = await PackageInfo.fromPlatform();
setState(() {
_packageInfo = info;
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
});
debugPrint('获取应用信息失败: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('PackageInfo Plus 示例'),
centerTitle: true,
elevation: 0,
),
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFFE8F4FF),
Color(0xFFF8F9FF),
],
),
),
child: SafeArea(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _packageInfo == null
? const Center(child: Text('获取应用信息失败'))
: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildAppCard(),
const SizedBox(height: 24),
_buildSectionTitle('应用信息'),
const SizedBox(height: 12),
_buildInfoGrid(),
const SizedBox(height: 24),
_buildSectionTitle('功能示例'),
const SizedBox(height: 12),
_buildFeatureButtons(),
],
),
),
),
),
);
}
Widget _buildAppCard() {
return Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF6366F1), Color(0xFF8B5CF6)],
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: const Color(0xFF6366F1).withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
),
child: const Icon(Icons.apps, size: 48, color: Colors.white),
),
const SizedBox(height: 16),
Text(
_packageInfo!.appName,
style: const TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'v${_packageInfo!.version} (${_packageInfo!.buildNumber})',
style: const TextStyle(color: Colors.white),
),
),
],
),
);
}
Widget _buildSectionTitle(String title) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF6366F1), Color(0xFF8B5CF6)],
),
borderRadius: BorderRadius.circular(8),
),
child: Text(
title,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
);
}
Widget _buildInfoGrid() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
),
],
),
child: Column(
children: [
_buildInfoRow('应用名称', _packageInfo!.appName, Icons.apps),
const Divider(height: 24),
_buildInfoRow('包名', _packageInfo!.packageName, Icons.inventory_2),
const Divider(height: 24),
_buildInfoRow('版本号', _packageInfo!.version, Icons.verified),
const Divider(height: 24),
_buildInfoRow('构建号', _packageInfo!.buildNumber, Icons.build),
if (_packageInfo!.buildSignature.isNotEmpty) ...[
const Divider(height: 24),
_buildInfoRow('签名', _truncateSignature(_packageInfo!.buildSignature), Icons.key),
],
],
),
);
}
Widget _buildInfoRow(String label, String value, IconData icon) {
return Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xFF6366F1).withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, size: 20, color: const Color(0xFF6366F1)),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: const TextStyle(color: Colors.grey, fontSize: 12)),
const SizedBox(height: 2),
Text(
value,
style: const TextStyle(fontWeight: FontWeight.w500),
overflow: TextOverflow.ellipsis,
),
],
),
),
],
);
}
String _truncateSignature(String signature) {
if (signature.length > 20) {
return '${signature.substring(0, 20)}...';
}
return signature;
}
Widget _buildFeatureButtons() {
return Column(
children: [
Row(
children: [
Expanded(
child: _buildFeatureCard(
'关于页面',
Icons.info,
Colors.blue,
() => _showAboutDialog(),
),
),
const SizedBox(width: 12),
Expanded(
child: _buildFeatureCard(
'版本检查',
Icons.update,
Colors.green,
() => _checkForUpdate(),
),
),
],
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: _buildFeatureCard(
'复制信息',
Icons.copy,
Colors.purple,
() => _copyInfo(),
),
),
const SizedBox(width: 12),
Expanded(
child: _buildFeatureCard(
'分享信息',
Icons.share,
Colors.orange,
() => _shareInfo(),
),
),
],
),
],
);
}
Widget _buildFeatureCard(
String title,
IconData icon,
Color color,
VoidCallback onTap,
) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
),
],
),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, color: color, size: 28),
),
const SizedBox(height: 12),
Text(
title,
style: const TextStyle(fontWeight: FontWeight.w500),
),
],
),
),
);
}
void _showAboutDialog() {
showAboutDialog(
context: context,
applicationName: _packageInfo!.appName,
applicationVersion: '${_packageInfo!.version} (${_packageInfo!.buildNumber})',
applicationIcon: Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: const Color(0xFF6366F1),
borderRadius: BorderRadius.circular(12),
),
child: const Icon(Icons.apps, color: Colors.white),
),
children: [
Text('包名: ${_packageInfo!.packageName}'),
],
);
}
void _checkForUpdate() {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('当前已是最新版本 ${_packageInfo!.version}'),
backgroundColor: Colors.green,
),
);
}
void _copyInfo() {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('应用信息已复制到剪贴板')),
);
}
void _shareInfo() {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('分享功能已触发')),
);
}
}
八、常见问题与解决方案
8.1 获取信息失败
问题原因:
- 平台未正确初始化
- 依赖未正确配置
解决方案:
dart
// 确保在 Widget 构建后获取信息
Future<void> _loadPackageInfo() async {
try {
final info = await PackageInfo.fromPlatform();
setState(() {
_packageInfo = info;
});
} catch (e) {
debugPrint('获取应用信息失败: $e');
}
}
8.2 版本号显示不正确
问题原因:
- pubspec.yaml 中的版本号格式不正确
- 平台配置文件中的版本号未更新
解决方案:
确保 pubspec.yaml 中的版本号格式正确:
yaml
version: 1.0.0+1
格式说明:版本号+构建号
8.3 应用名称显示为空
问题原因:
- OpenHarmony 平台配置中未设置应用名称
解决方案:
检查 OpenHarmony 配置文件 ohos/entry/src/main/module.json5:
json
{
"module": {
"abilities": [
{
"label": "你的应用名称"
}
]
}
}
九、总结
package_info_plus 是 Flutter for OpenHarmony 应用开发中常用的应用信息获取组件。通过本文的学习,我们掌握了:
- 基础用法:获取应用名称、版本号、包名等信息
- API 详解:PackageInfo 类的属性和方法
- 实际应用:关于页面、版本检查、用户反馈、日志记录等场景
- 常见问题:获取失败、版本号不正确等问题的解决方案
💡 开发建议:使用 package_info_plus 时应注意:
- 在应用启动时初始化并缓存信息
- 版本号格式应遵循语义化版本规范
- 在用户反馈中附带版本信息便于排查问题
- 定期更新版本号以反映应用变更