Flutter动态图标更新插件dynamic_icon_flutter的使用
Flutter动态图标更新插件dynamic_icon_flutter的使用
flutter_dynamic_icon
是一个用于在移动平台上动态更改应用程序图标的Flutter插件,支持iOS(版本 > 10.3)和Android。
已知问题
- 每个Android版本的行为可能不同,在Android 8上,您可能会注意到图标变化需要几秒钟。
- 在某些Android版本中使用此功能会导致您的应用程序崩溃(第一次更改图标时会崩溃,之后不会),这种用户体验不佳,您可以在这里了解更多关于此问题的信息。
Android集成
步骤
- 在
pubspec.yaml
文件中的依赖项部分添加最新版本的插件。 - 执行
flutter pub get
。 - 更新
android/src/main/AndroidManifest.xml
如下:
<application ...>
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:enabled="true">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- FOR NOW USE "icon_1" AS ALTERNATIVE ICON NAME -->
<activity-alias
android:label="Your app"
android:icon="@mipmap/ic_launcher_1"
android:name=".icon_1"
android:enabled="false"
android:targetActivity=".MainActivity">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application>
- 可以拥有多个应用图标,在应用程序中可以使用:
- 方法中传递的名称必须在
AndroidManifest.xml
中,并且对于每个图标,必须在AndroidManifest.xml
中声明一个activity-alias
。 - 声明一个字符串列表(可用的应用图标)。
- 别忘了将
MainActivity
添加到列表中。
- 方法中传递的名称必须在
const List<String> list = ["icon_1", "icon_2", "icon_n", "MainActivity"];
DynamicIconFlutter.setIcon(icon: 'icon_1', listAvailableIcon: list);
iOS集成
步骤
- 放置一些用于应用图标的图片,例如
teamfortress@2x.png
,teamfortress@3x.png
等。这些图标不应放在Assets.xcassets
文件夹中,而是放在外面。 - 设置
Info.plist
:- 添加
Icon files (iOS 5)
到信息属性列表。 - 添加
CFBundleAlternateIcons
作为字典,用于替代图标。 - 设置3个字典在
CFBundleAlternateIcons
下,分别对应teamfortress
、photos
和chills
。 - 对于每个字典,配置两个属性——
UIPrerenderedIcon
和CFBundleIconFiles
。
- 添加
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>chills</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>chills</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>photos</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>photos</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>teamfortress</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>teamfortress</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>chills</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
现在,您可以调用DynamicIconFlutter.setAlternateIconName
并传入CFBundleAlternateIcons
键作为参数来设置该图标。
Dart/Flutter集成
从Dart代码中,您需要导入插件并使用其静态方法:
import 'package:dynamic_icon_flutter/dynamic_icon_flutter.dart';
try {
if (await DynamicIconFlutter.supportsAlternateIcons) {
await DynamicIconFlutter.setAlternateIconName("photos");
print("App icon change successful");
return;
}
} on PlatformException catch (e) {
if (await DynamicIconFlutter.supportsAlternateIcons) {
await DynamicIconFlutter.setAlternateIconName(null);
print("Change app icon back to default");
return;
} else {
print("Failed to change app icon");
}
}
示例代码
下面是一个完整的示例代码,展示了如何在Flutter应用中使用dynamic_icon_flutter
插件:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:dynamic_icon_flutter/dynamic_icon_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String currentIconName = "?";
@override
void initState() {
super.initState();
DynamicIconFlutter.getAlternateIconName().then((v) {
setState(() {
currentIconName = v ?? "`primary`";
});
});
}
@override
Widget build(BuildContext context) {
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('Dynamic App Icon'),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 28),
child: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Current Icon Name: $currentIconName",
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4,
),
),
OutlineButton.icon(
icon: const Icon(Icons.ac_unit),
label: const Text("Team Fortress"),
onPressed: () async {
try {
if (await DynamicIconFlutter.supportsAlternateIcons) {
await DynamicIconFlutter.setAlternateIconName("teamfortress");
_scaffoldKey.currentState?.hideCurrentSnackBar();
_scaffoldKey.currentState?.showSnackBar(const SnackBar(
content: Text("App icon change successful"),
));
DynamicIconFlutter.getAlternateIconName().then((v) {
setState(() {
currentIconName = v ?? "`primary`";
});
});
return;
}
} on PlatformException catch (e) {
print(e.toString());
_scaffoldKey.currentState?.hideCurrentSnackBar();
_scaffoldKey.currentState?.showSnackBar(const SnackBar(
content: Text("Failed to change app icon"),
));
}
},
),
OutlineButton.icon(
icon: const Icon(Icons.ac_unit),
label: const Text("Photos"),
onPressed: () async {
try {
if (await DynamicIconFlutter.supportsAlternateIcons) {
await DynamicIconFlutter.setAlternateIconName("photos");
_scaffoldKey.currentState?.hideCurrentSnackBar();
_scaffoldKey.currentState?.showSnackBar(const SnackBar(
content: Text("App icon change successful"),
));
DynamicIconFlutter.getAlternateIconName().then((v) {
setState(() {
currentIconName = v ?? "`primary`";
});
});
return;
}
} on PlatformException catch (e) {
_scaffoldKey.currentState?.hideCurrentSnackBar();
_scaffoldKey.currentState?.showSnackBar(const SnackBar(
content: Text("Failed to change app icon"),
));
}
},
),
OutlineButton.icon(
icon: const Icon(Icons.ac_unit),
label: const Text("Chills"),
onPressed: () async {
try {
if (await DynamicIconFlutter.supportsAlternateIcons) {
await DynamicIconFlutter.setAlternateIconName("chills");
_scaffoldKey.currentState?.hideCurrentSnackBar();
_scaffoldKey.currentState?.showSnackBar(const SnackBar(
content: Text("App icon change successful"),
));
DynamicIconFlutter.getAlternateIconName().then((v) {
setState(() {
currentIconName = v ?? "`primary`";
});
});
return;
}
} on PlatformException catch (e) {
_scaffoldKey.currentState?.hideCurrentSnackBar();
_scaffoldKey.currentState?.showSnackBar(const SnackBar(
content: Text("Failed to change app icon"),
));
}
},
),
const SizedBox(
height: 28,
),
OutlineButton.icon(
icon: const Icon(Icons.restore_outlined),
label: const Text("Restore Icon"),
onPressed: () async {
try {
if (await DynamicIconFlutter.supportsAlternateIcons) {
await DynamicIconFlutter.setAlternateIconName(null);
_scaffoldKey.currentState?.hideCurrentSnackBar();
_scaffoldKey.currentState?.showSnackBar(const SnackBar(
content: Text("App icon restore successful"),
));
DynamicIconFlutter.getAlternateIconName().then((v) {
setState(() {
currentIconName = v ?? "`primary`";
});
});
return;
}
} on PlatformException catch (e) {
_scaffoldKey.currentState?.hideCurrentSnackBar();
_scaffoldKey.currentState?.showSnackBar(const SnackBar(
content: Text("Failed to change app icon"),
));
}
},
),
],
),
),
),
);
}
}
通过上述步骤和示例代码,您应该能够在Flutter应用中成功实现动态图标更新的功能。希望这对您有所帮助!
更多关于Flutter动态图标更新插件dynamic_icon_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter动态图标更新插件dynamic_icon_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用dynamic_icon_flutter
插件来动态更新应用图标的示例代码。请注意,这个插件的功能和可用性可能会随着版本更新而变化,因此请参考最新的官方文档以确保最佳实践。
首先,确保你已经在pubspec.yaml
文件中添加了dynamic_icon_flutter
依赖:
dependencies:
flutter:
sdk: flutter
dynamic_icon_flutter: ^最新版本号 # 请替换为最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,在你的Flutter项目中,你可以按照以下步骤使用dynamic_icon_flutter
插件:
- 导入插件
在你的Dart文件中导入插件:
import 'package:dynamic_icon_flutter/dynamic_icon_flutter.dart';
- 请求动态图标权限
在Android上,你需要在AndroidManifest.xml
中请求CHANGE_APP_ICON
权限(如果插件需要的话,通常插件会处理这部分)。
<uses-permission android:name="com.android.launcher.permission.CHANGE_APP_ICON" />
此外,你可能需要在MainActivity.kt
或MainActivity.java
中处理一些初始化逻辑(具体取决于插件的要求)。
- 设置动态图标
以下是一个简单的示例,展示如何使用dynamic_icon_flutter
来更改应用图标:
import 'package:flutter/material.dart';
import 'package:dynamic_icon_flutter/dynamic_icon_flutter.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Dynamic Icon Example'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
try {
// 检查是否支持动态图标
bool isSupported = await DynamicIconFlutter.isSupported();
if (isSupported) {
// 设置新的图标(假设你有一个名为'new_icon.png'的图标文件放在assets中)
await DynamicIconFlutter.setAppIcon(
iconName: 'assets/new_icon.png',
);
// 提示用户图标已更改
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('App icon changed successfully!')),
);
} else {
// 提示用户设备不支持动态图标
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('This device does not support dynamic icons.')),
);
}
} catch (e) {
// 处理错误
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to change app icon: $e')),
);
}
},
child: Text('Change App Icon'),
),
),
),
);
}
}
在上面的代码中,我们首先检查设备是否支持动态图标。如果支持,我们尝试将应用图标更改为assets/new_icon.png
。注意,你需要将new_icon.png
文件添加到你的assets
目录中,并在pubspec.yaml
中正确配置它:
flutter:
assets:
- assets/new_icon.png
- 处理图标变化后的逻辑
某些平台(如iOS)可能需要额外的配置或代码来处理图标变化后的逻辑,例如通知系统图标缓存已更改。这些步骤通常会在插件的官方文档中有详细说明。
- 测试
最后,不要忘记在支持动态图标的设备上测试你的应用,以确保一切正常工作。
请注意,由于动态图标功能可能涉及操作系统的限制和权限要求,因此在实际部署之前,务必进行充分的测试,并遵循相关平台的最佳实践。