Flutter+Android/ios 桌面小組件
總結(jié):
- Android和iOS 桌面小組件 需要原生去繪制小組件和更新數(shù)據(jù),F(xiàn)lutter層 可以使用 MethodChannel 與原生 通信 來控制 更新數(shù)據(jù),app無法主動控制 小組件的添加 和 刪除, 只能是用戶手動操作 。
- 小組件支持顯示的內(nèi)容包括:文字,圖片,列表,虛擬時鐘,勾選框,進度條等,注意:只能顯示原生的view 不可顯示自定義畫的view。
- 負一屏:Google原生暫時還沒開放API可以直接添加小組件到負一屏,目前Google原生的負一屏 是一個簡單的 新聞 feed流 不可自定義編輯,國內(nèi)的很多廠商整合了負一屏和桌面小組件,也就說小組件可以直接添加在負一屏,不過開發(fā)需要適配不同的廠商系統(tǒng)如小米,華為,Oppo,vivo等,iOS負一屏 也可以自定義編輯,小組件直接添加在負一屏。
官方文檔:
Android小組件:https://developer.android.com/develop/ui/views/appwidgets?hl=zh-cn
IOS小組件:https://developer.apple.com/cn/documentation/widgetkit/creating-a-widget-extension/
小米小部件:https://dev.mi.com/console/doc/detail?pId=2465
華為榮耀小組件:https://developer.honor.com/cn/doc/guides/100170
Oppo小組件:https://open.oppomobile.com/new/developmentDoc/info?id=12704
vivo小組件:https://developers.vivo.com/doc/d/e88425fe41c94924a052e98dd956c0fb
參考文檔:
Flutter小組件開發(fā):https://juejin.cn/post/6933559401462628365
Android小組件開發(fā):https://juejin.cn/post/7296031991320870912
上手開發(fā):
使用Flutter插件:home_widget
插件地址:https://pub-web.flutter-io.cn/packages/home_widget
| iOS | Android |
|---|---|
![]() iOS.png
|
![]() Android.png
|
平臺設置
為了正常工作,需要一些特定于平臺的設置。請查看以下內(nèi)容,了解如何添加對 Android 和 iOS 的支持
<details><summary>iOS</summary>
在 Xcode 中將小部件添加到您的應用程序
通過添加小部件擴展 <kbd>File</kbd> > <kbd>New</kbd> > <kbd>Target</kbd> > <kbd>Widget Extension</kbd>

添加groupId
您需要向應用程序和小部件擴展添加一個groupId
注意:為了添加 groupId,您需要一個付費的 Apple 開發(fā)者帳戶
轉(zhuǎn)到您的Apple 開發(fā)者帳戶并添加一個新組。將此組添加到您的 Runner 和 XCode 內(nèi)的 Widget Extension: <kbd>Signing & Capabilities</kbd> > <kbd>App Groups</kbd> > <kbd>+</kbd>。
(要在您的應用程序和擴展程序之間交換,請更改目標)

同步 CFBundleVersion(可選)
此步驟是可選的,這會將小部件擴展構(gòu)建版本與您的應用程序版本同步,因此您在上傳應用程序時不會收到 App Store Connect 版本不匹配的警告。

在您的 Runner(應用程序)目標中,轉(zhuǎn)到 <kbd>Build Phases</kbd> > <kbd>+</kbd> > <kbd>New Run Script Phase</kbd> 并添加以下腳本:
generatedPath="$SRCROOT/Flutter/Generated.xcconfig"
# Read and trim versionNumber and buildNumber
versionNumber=$(grep FLUTTER_BUILD_NAME "$generatedPath" | cut -d '=' -f2 | xargs)
buildNumber=$(grep FLUTTER_BUILD_NUMBER "$generatedPath" | cut -d '=' -f2 | xargs)
infoPlistPath="$SRCROOT/HomeExampleWidget/Info.plist"
# Check and add CFBundleVersion if it does not exist
/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$infoPlistPath" 2>/dev/null
if [ $? != 0 ]; then
/usr/libexec/PlistBuddy -c "Add :CFBundleVersion string $buildNumber" "$infoPlistPath"
else
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$infoPlistPath"
fi
# Check and add CFBundleShortVersionString if it does not exist
/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$infoPlistPath" 2>/dev/null
if [ $? != 0 ]; then
/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string $versionNumber" "$infoPlistPath"
else
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $versionNumber" "$infoPlistPath"
fi
將HomeExampleWidget 替換為您創(chuàng)建的小部件擴展文件夾的名稱。
編寫你的小組件
Check the Example App for an Implementation of a Widget.
A more detailed overview on how to write Widgets for iOS 14 can be found on the Apple Developer documentation.
In order to access the Data send with Flutter can be access with
檢查示例應用程序以了解小部件的實現(xiàn)。有關(guān)如何為 iOS 14 編寫 Widget 的更詳細概述可以在Apple 開發(fā)人員文檔中找到。為了訪問使用 Flutter 發(fā)送的數(shù)據(jù),可以使用
let data = UserDefaults.init(suiteName:"YOUR_GROUP_ID")
</details>
<details><summary>Android (Jetpack Glance)</summary>
將 Jetpack Glance 添加為應用程序 Gradle 文件的依賴項
implementation 'androidx.glance:glance-appwidget:LATEST-VERSION'
在 android/app/src/main/res/xml中創(chuàng)建小部件配置
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout"
android:minWidth="40dp"
android:minHeight="40dp"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="10000">
</appwidget-provider>
將 WidgetReceiver 添加到 AndroidManifest
<receiver android:name=".glance.HomeWidgetReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/home_widget_glance_example" />
</receiver>
創(chuàng)建 WidgetReceiver
要獲得自動更新,您應該從 HomeWidgetGlanceWidgetReceiver 擴展
Your Receiver should then look like this
你的Receiver 應該看起來像這樣
package es.antonborri.home_widget_example.glance
import HomeWidgetGlanceWidgetReceiver
class HomeWidgetReceiver : HomeWidgetGlanceWidgetReceiver<HomeWidgetGlanceAppWidget>() {
override val glanceAppWidget = HomeWidgetGlanceAppWidget()
}
構(gòu)建您的 AppWidget
class HomeWidgetGlanceAppWidget : GlanceAppWidget() {
/**
* Needed for Updating
*/
override val stateDefinition = HomeWidgetGlanceStateDefinition()
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
GlanceContent(context, currentState())
}
}
@Composable
private fun GlanceContent(context: Context, currentState: HomeWidgetGlanceState) {
// Use data to access the data you save with
val data = currentState.preferences
// Build Your Composable Widget
Column(
...
}
Android (XML)
在 android/app/src/main/res/layout中創(chuàng)建小部件布局
在 android/app/src/main/res/xml中創(chuàng)建小部件配置
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp"
android:minHeight="40dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/example_layout"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen">
</appwidget-provider>
將 WidgetReceiver 添加到 AndroidManifest
<receiver android:name="HomeWidgetExampleProvider" android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/home_widget_example" />
</receiver>
編寫你的 WidgetProvider
For convenience, you can extend from HomeWidgetProvider which gives you access to a SharedPreferences Object with the Data in the onUpdate method.
In case you don't want to use the convenience Method you can access the Data using
為了方便起見,您可以從HomeWidgetProvider進行擴展,它使您可以通過onUpdate方法中的數(shù)據(jù)訪問 SharedPreferences 對象。如果您不想使用方便的方法,您可以使用以下方式訪問數(shù)據(jù)
import es.antonborri.home_widget.HomeWidgetPlugin
...
HomeWidgetPlugin.getData(context)
這將使您可以訪問相同的 SharedPreferences
更多信息
For more Information on how to create and configure Android Widgets, check out this guide on the Android Developers Page.
有關(guān)如何創(chuàng)建和配置 Android Widget 的更多信息,請查看 Android 開發(fā)人員頁面上的本指南。
用法
設置
iOS
For iOS, you need to call HomeWidget.setAppGroupId('YOUR_GROUP_ID');
Without this you won't be able to share data between your App and the Widget and calls to saveWidgetData and getWidgetData will return an error
對于iOS,您需要調(diào)用HomeWidget.setAppGroupId('YOUR_GROUP_ID');如果沒有這個,您將無法在應用程序和小部件之間共享數(shù)據(jù),并且調(diào)用saveWidgetData和getWidgetData將返回錯誤
保存數(shù)據(jù)
In order to save Data call HomeWidget.saveWidgetData<String>('id', data)
更新小組件
In order to force a reload of the HomeScreenWidget you need to call
為了強制重新加載 HomeScreenWidget,您需要調(diào)用
HomeWidget.updateWidget(
name: 'HomeWidgetExampleProvider',
androidName: 'HomeWidgetExampleProvider',
iOSName: 'HomeWidgetExample',
qualifiedAndroidName: 'com.example.app.HomeWidgetExampleProvider',
);
The name for Android will be chosen by checking qualifiedAndroidName, falling back to <packageName>.androidName and if that was not provided it will fallback to <packageName>.name.
This Name needs to be equal to the Classname of the WidgetProvider
Android 的名稱將通過檢查qualifiedAndroidName來選擇,回退到<packageName>.androidName ,如果未提供,它將回退到<packageName>.name 。該名稱需要等于WidgetProvider的類名
The name for iOS will be chosen by checking iOSName if that was not provided it will fallback to name.
This name needs to be equal to the Kind specified in you Widget
iOS 的名稱將通過檢查iOSName來選擇,如果未提供,它將回退到name 。該名稱需要等于您在 Widget 中指定的 Kind
Android (Jetpack Glance)
If you followed the guide and use HomeWidgetGlanceWidgetReceiver as your Receiver, HomeWidgetGlanceStateDefinition as the AppWidgetStateDefinition, currentState() in the composable view and currentState.preferences for data access. No further work is necessary.
如果您按照指南操作并使用HomeWidgetGlanceWidgetReceiver作為接收器、使用HomeWidgetGlanceStateDefinition作為 AppWidgetStateDefinition、可組合視圖中的currentState()以及用于數(shù)據(jù)訪問的currentState.preferences 。不需要進一步的工作。
Android (XML)
Calling HomeWidget.updateWidget only notifies the specified provider.
To update widgets using this provider,
update them from the provider like this:
調(diào)用HomeWidget.updateWidget僅通知指定的提供程序。要使用此提供程序更新小部件,請從提供程序更新它們,如下所示:
class HomeWidgetExampleProvider : HomeWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
appWidgetIds.forEach { widgetId ->
val views = RemoteViews(context.packageName, R.layout.example_layout).apply {
// ...
}
// Update widget.
appWidgetManager.updateAppWidget(widgetId, views)
}
}
}
檢索數(shù)據(jù)
To retrieve the current Data saved in the Widget call HomeWidget.getWidgetData<String>('id', defaultValue: data)
要檢索保存在小部件中的當前數(shù)據(jù),請調(diào)用HomeWidget.getWidgetData<String>('id', defaultValue: data)
交互式小部件
Android 和 iOS(從 iOS 17 開始)允許小部件具有按鈕等交互式元素
<details><summary>Dart</summary>
-
Write a static function that takes a Uri as an argument. This will get called when a user clicks on the View
編寫一個以 Uri 作為參數(shù)的靜態(tài)函數(shù)。當用戶單擊視圖時將調(diào)用此函數(shù)@pragma("vm:entry-point") FutureOr<void> backgroundCallback(Uri data) async { // do something with data ... }@pragma('vm:entry-point')must be placed above thecallbackfunction to avoid tree shaking in release mode. -
Register the callback function by calling
通過調(diào)用注冊回調(diào)函數(shù)HomeWidget.registerInteractivityCallback(backgroundCallback);
iOS
-
Adjust your Podfile to add
home_widgetas a dependency to your WidgetExtension
調(diào)整 Podfile 以將home_widget添加為 WidgetExtension 的依賴項target 'YourWidgetExtension' do use_frameworks! use_modular_headers! pod 'home_widget', :path => '.symlinks/plugins/home_widget/ios' end -
To be able to use plugins with the Background Callback add this to your AppDelegate's
applicationfunction
為了能夠通過后臺回調(diào)使用插件,請將其添加到您的 AppDelegate 的application函數(shù)中if #available(iOS 17, *) { HomeWidgetBackgroundWorker.setPluginRegistrantCallback { registry in GeneratedPluginRegistrant.register(with: registry) } } -
Create a custom
AppIntentin your App Target (Runner) and make sure to select both your App and your WidgetExtension in the Target Membership panel
在您的 App Target (Runner) 中創(chuàng)建自定義AppIntent ,并確保在 Target Membership 面板中選擇您的 App 和 WidgetExtensioned465c7f-5287-433d-b051-02fc8f80267a.png
In this Intent you should import home_widget and call HomeWidgetBackgroundWorker.run(url: url, appGroup: appGroup!) in the perform method. url and appGroup can be either hardcoded or set as parameters from the Widget
在此 Intent 中,您應該導入home_widget并在執(zhí)行方法中調(diào)用HomeWidgetBackgroundWorker.run(url: url, appGroup: appGroup!) 。 url和appGroup可以是硬編碼的,也可以設置為 Widget 的參數(shù)
import AppIntents
import Flutter
import Foundation
import home_widget
@available(iOS 16, *)
public struct BackgroundIntent: AppIntent {
static public var title: LocalizedStringResource = "HomeWidget Background Intent"
@Parameter(title: "Widget URI")
var url: URL?
@Parameter(title: "AppGroup")
var appGroup: String?
public init() {}
public init(url: URL?, appGroup: String?) {
self.url = url
self.appGroup = appGroup
}
public func perform() async throws -> some IntentResult {
await HomeWidgetBackgroundWorker.run(url: url, appGroup: appGroup!)
return .result()
}
}
-
Add a Button to your Widget. This Button might be encapsulated by a Version check. Pass in an instance of the
AppIntentcreated in the previous step
將按鈕添加到您的小部件。該按鈕可能由版本檢查封裝。傳入上一步創(chuàng)建的AppIntent實例Button( intent: BackgroundIntent( url: URL(string: "homeWidgetExample://titleClicked"), appGroup: widgetGroupId) ) { Text(entry.title).bold().font( /*@START_MENU_TOKEN@*/.title /*@END_MENU_TOKEN@*/) }.buttonStyle(.plain) -
With the current setup the Widget is now Interactive as long as the App is still in the background. If you want to have the Widget be able to wake the App up you need to add the following to your
AppIntentfile
在當前設置下,只要應用程序仍在后臺,小部件就可以交互。如果您想讓 Widget 能夠喚醒應用程序,您需要將以下內(nèi)容添加到您的AppIntent文件中@available(iOS 16, *) @available(iOSApplicationExtension, unavailable) extension BackgroundIntent: ForegroundContinuableIntent {}This code tells the system to always perform the Intent in the App and not in a process attached to the Widget. Note however that this will start your Flutter App using the normal main entrypoint meaning your full app might be run in the background. To counter this you should add checks in the very first Widget you build inside
runAppto only perform necessary calls/setups while the App is launched in the background
此代碼告訴系統(tǒng)始終在應用程序中執(zhí)行 Intent,而不是在附加到 Widget 的進程中。但請注意,這將使用正常的主入口點啟動您的 Flutter 應用程序,這意味著您的完整應用程序可能會在后臺運行。為了解決這個問題,您應該在runApp內(nèi)構(gòu)建的第一個 Widget 中添加檢查,以便僅在應用程序在后臺啟動時執(zhí)行必要的調(diào)用/設置
Android Jetpack Glance
- Add the necessary Receiver and Service to your
AndroidManifest.xmlfile
將必要的接收器和服務添加到您的AndroidManifest.xml文件中<receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver" android:exported="true"> <intent-filter> <action android:name="es.antonborri.home_widget.action.BACKGROUND" /> </intent-filter> </receiver> <service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true"/> - Create a custom Action 創(chuàng)建自定義操作
class InteractiveAction : ActionCallback { override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) { val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(context, Uri.parse("homeWidgetExample://titleClicked")) backgroundIntent.send() } } - Add the Action as a modifier to a view
將操作作為修改器添加到視圖中Text( title, style = TextStyle(fontSize = 36.sp, fontWeight = FontWeight.Bold), modifier = GlanceModifier.clickable(onClick = actionRunCallback<InteractiveAction>()), )
Android XML
-
Add the necessary Receiver and Service to your
AndroidManifest.xmlfile
將必要的接收器和服務添加到您的AndroidManifest.xml文件中<receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver" android:exported="true"> <intent-filter> <action android:name="es.antonborri.home_widget.action.BACKGROUND" /> </intent-filter> </receiver> <service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true"/> -
Add a
HomeWidgetBackgroundIntent.getBroadcastPendingIntent to the View you want to add a click listener to
將HomeWidgetBackgroundIntent.getBroadcast PendingIntent 添加到要添加點擊偵聽器的視圖val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( context, Uri.parse("homeWidgetExample://titleClicked") ) setOnClickPendingIntent(R.id.widget_title, backgroundIntent)
Using images of Flutter widgets (使用 Flutter 小組件的圖像)
In some cases, you may not want to rewrite UI code in the native frameworks for your widgets.
在某些情況下,您可能不想在小部件的本機框架中重寫 UI 代碼。
Dart
For example, say you have a chart in your Flutter app configured with CustomPaint:
例如,假設您的 Flutter 應用程序中有一個配置了“CustomPaint”的圖表:
class LineChart extends StatelessWidget {
const LineChart({
super.key,
});
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: LineChartPainter(),
child: const SizedBox(
height: 200,
width: 200,
),
);
}
}

Rewriting the code to create this chart on both Android and iOS might be time consuming.
Instead, you can generate a png file of the Flutter widget and save it to a shared container
between your Flutter app and the home screen widget.
重寫代碼以在 Android 和 iOS 上創(chuàng)建此圖表可能非常耗時。相反,您可以生成 Flutter 小部件的 png 文件,并將其保存到 Flutter 應用程序和主屏幕小部件之間的共享容器中。
var path = await HomeWidget.renderFlutterWidget(
const LineChart(),
key: 'lineChart',
logicalSize: const Size(400, 400),
);
-
LineChart()is the widget that will be rendered as an image. (LineChart()是將呈現(xiàn)為圖像的小部件。) -
keyis the key in the key/value storage on the device that stores the path of the file for easy retrieval on the native side.(key是設備上鍵/值存儲中的鍵,存儲文件的路徑,方便本機端檢索)
</details>
iOS
To retrieve the image and display it in a widget, you can use the following SwiftUI code:
要檢索圖像并將其顯示在小部件中,您可以使用以下 SwiftUI 代碼:
-
In your
TimelineEntrystruct add a property to retrieve the path:
在您的TimelineEntry結(jié)構(gòu)中添加一個屬性來檢索路徑:struct MyEntry: TimelineEntry { … let lineChartPath: String } -
Get the path from the
UserDefaultsingetSnapshot:
從getSnapshot中的UserDefaults獲取路徑:func getSnapshot( ... let lineChartPath = userDefaults?.string(forKey: "lineChart") ?? "No screenshot available" -
Create a
Viewto display the chart and resize the image based on thedisplaySizeof the widget:
創(chuàng)建一個View來顯示圖表并根據(jù)小部件的displaySize調(diào)整圖像大小:struct WidgetEntryView : View { … var ChartImage: some View { if let uiImage = UIImage(contentsOfFile: entry.lineChartPath) { let image = Image(uiImage: uiImage) .resizable() .frame(width: entry.displaySize.height*0.5, height: entry.displaySize.height*0.5, alignment: .center) return AnyView(image) } print("The image file could not be loaded") return AnyView(EmptyView()) } … } -
Display the chart in the body of the widget's
View:
在小部件的View主體中顯示圖表:VStack { Text(entry.title) Text(entry.description) ChartImage }

Android (Jetpack Glance)
// Access data
val data = currentState.preferences
// Get Path
val imagePath = data.getString("lineChart", null)
// Add Image to Compose Tree
imagePath?.let {
val bitmap = BitmapFactory.decodeFile(it)
Image(androidx.glance.ImageProvider(bitmap), null)
}
Android (XML)
-
Add an image UI element to your xml file:
將圖像 UI 元素添加到您的 xml 文件中:<ImageView android:id="@+id/widget_image" android:layout_width="200dp" android:layout_height="200dp" android:layout_below="@+id/headline_description" android:layout_alignBottom="@+id/headline_title" android:layout_alignParentStart="true" android:layout_alignParentLeft="true" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="6dp" android:layout_marginBottom="-134dp" android:layout_weight="1" android:adjustViewBounds="true" android:background="@android:color/white" android:scaleType="fitCenter" android:src="@android:drawable/star_big_on" android:visibility="visible" tools:visibility="visible" /> -
Update your Kotlin code to get the chart image and put it into the widget, if it exists.
更新您的 Kotlin 代碼以獲取圖表圖像并將其放入小部件(如果存在)中。class NewsWidget : AppWidgetProvider() { override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, ) { for (appWidgetId in appWidgetIds) { // Get reference to SharedPreferences val widgetData = HomeWidgetPlugin.getData(context) val views = RemoteViews(context.packageName, R.layout.news_widget).apply { // Get chart image and put it in the widget, if it exists val imagePath = widgetData.getString("lineChart", null) val imageFile = File(imagePath) val imageExists = imageFile.exists() if (imageExists) { val myBitmap: Bitmap = BitmapFactory.decodeFile(imageFile.absolutePath) setImageViewBitmap(R.id.widget_image, myBitmap) } else { println("image not found!, looked @: $imagePath") } // End new code } appWidgetManager.updateAppWidget(appWidgetId, views) } } }
啟動應用程序并檢測哪個小部件被點擊
To detect if the App has been initially started by clicking the Widget you can call HomeWidget.initiallyLaunchedFromHomeWidget() if the App was already running in the Background you can receive these Events by listening to HomeWidget.widgetClicked. Both methods will provide Uris, so you can easily send back data from the Widget to the App to for example navigate to a content page.
要檢測應用程序是否已通過單擊小部件初始啟動,您可以調(diào)用HomeWidget.initiallyLaunchedFromHomeWidget()如果應用程序已經(jīng)在后臺運行,您可以通過監(jiān)聽HomeWidget.widgetClicked來接收這些事件。兩種方法都會提供 Uris,因此您可以輕松地將數(shù)據(jù)從 Widget 發(fā)送回應用程序,例如導航到內(nèi)容頁面。
In order for these methods to work you need to follow these steps:
為了使這些方法發(fā)揮作用,您需要執(zhí)行以下步驟:
iOS
Add .widgetUrl to your WidgetComponent
將.widgetUrl添加到您的 WidgetComponent
Text(entry.message)
.font(.body)
.widgetURL(URL(string: "homeWidgetExample://message?message=\(entry.message)&homeWidget"))
In order to only detect Widget Links you need to add the queryParameterhomeWidget to the URL
為了僅檢測 Widget 鏈接,您需要將 queryParameter homeWidget添加到 URL
</details>
Android Jetpack Glance
Add an IntentFilter to the Activity Section in your AndroidManifest
將IntentFilter添加到AndroidManifest的Activity部分
<intent-filter>
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
</intent-filter>
Add the following modifier to your Widget (import from HomeWidget)
將以下修改器添加到您的小部件(從 HomeWidget 導入)
Text(
message,
style = TextStyle(fontSize = 18.sp),
modifier = GlanceModifier.clickable(
onClick = actionStartActivity<MainActivity>(
context,
Uri.parse("homeWidgetExample://message?message=$message")
)
)
)
Android XML
Add an IntentFilter to the Activity Section in your AndroidManifest
將IntentFilter添加到AndroidManifest的Activity部分
<intent-filter>
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
</intent-filter>
In your WidgetProvider add a PendingIntent to your View using HomeWidgetLaunchIntent.getActivity
在你的 WidgetProvider 中使用HomeWidgetLaunchIntent.getActivity添加一個 PendingIntent 到你的視圖中
val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homeWidgetExample://message?message=$message"))
setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData)
后臺更新
As the methods of HomeWidget are static it is possible to use HomeWidget in the background to update the Widget even when the App is in the background.
由于 HomeWidget 的方法是靜態(tài)的,因此即使應用程序在后臺,也可以在后臺使用 HomeWidget 來更新 Widget。
The example App is using the flutter_workmanager plugin to achieve this.
Please follow the Setup Instructions for flutter_workmanager (or your preferred background code execution plugin). Most notably make sure that Plugins get registered in iOS in order to be able to communicate with the HomeWidget Plugin.
In case of flutter_workmanager this achieved by adding:
示例應用程序使用flutter_workmanager插件來實現(xiàn)此目的。請遵循 flutter_workmanager(或您首選的后臺代碼執(zhí)行插件)的設置說明。最值得注意的是,請確保插件在 iOS 中注冊,以便能夠與 HomeWidget 插件進行通信。對于 flutter_workmanager,可以通過添加以下內(nèi)容來實現(xiàn):
WorkmanagerPlugin.setPluginRegistrantCallback { registry in
GeneratedPluginRegistrant.register(with: registry)
}
Request Pin Widget
Requests to Pin (Add) the Widget to the users HomeScreen by pinning it to the users HomeScreen.
請求通過將小部件固定到用戶主屏幕來將小部件固定(添加)到用戶主屏幕。
HomeWidget.requestPinWidget(
name: 'HomeWidgetExampleProvider',
androidName: 'HomeWidgetExampleProvider',
qualifiedAndroidName: 'com.example.app.HomeWidgetExampleProvider',
);
This method is only supported on Android, API 26+.
If you want to check whether it is supported on current device, use:
此方法僅在Android、API 26+上受支持。如果您想檢查當前設備是否支持它,請使用:
HomeWidget.isRequestPinWidgetSupported();


