abausg / home_widget Goto Github PK
View Code? Open in Web Editor NEWFlutter Package for Easier Creation of Home Screen Widgets
Flutter Package for Easier Creation of Home Screen Widgets
Is it possible to have multiple widgets that update in the background? I have managed to get two widgets, but cannot get one of them to update in the background.
I have two HomeWidgetProvider Classes, two widget info xml's, two layout xml's, and have two receivers in the manifest. I only have one of the following - I'm assuming this is okay?
<receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver"> <intent-filter> <action android:name="com.resortstylebeanbags.localweatherau.action.BACKGROUND" /> </intent-filter> </receiver> <service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true"/>
We have a widget that shows the current state, filllevel, ... of an energy storage Unit, and we would like to show either Status: OK in black or Status: ERROR in red?
The data for this widget comes from a rest api, is there any way to programmatically update the textfield to red background as soon as the api returns an error? As far as I could see there is only support for updateWidget and set the text and nothing else?
Hello,
I only do one thing,
It is import your library and run app,
After I exit app manually,
I got exception immediately, as image in below :
In case I don't import your library, It's okay
I'm sure this bug appear from previous version until latest version.
Please prevent this bug,
Thanks,
p/s : Please notice that I hasn't declare < receiver > tag in manifest xml yet_
I got these error logs :
D/AndroidRuntime(26991): Shutting down VM
E/AndroidRuntime(26991): FATAL EXCEPTION: main
E/AndroidRuntime(26991): java.lang.RuntimeException: Unable to destroy activity {.MainActivity}: java.lang.IllegalArgumentException: Receiver not registered: null
E/AndroidRuntime(26991): at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4203)
E/AndroidRuntime(26991): at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4221)
E/AndroidRuntime(26991): at android.app.ActivityThread.-wrap6(ActivityThread.java)
E/AndroidRuntime(26991): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1538)
E/AndroidRuntime(26991): at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(26991): at android.os.Looper.loop(Looper.java:154)
E/AndroidRuntime(26991): at android.app.ActivityThread.main(ActivityThread.java:6119)
E/AndroidRuntime(26991): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(26991): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
E/AndroidRuntime(26991): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
E/AndroidRuntime(26991): Caused by: java.lang.IllegalArgumentException: Receiver not registered: null
E/AndroidRuntime(26991): at android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:1007)
E/AndroidRuntime(26991): at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:1330)
E/AndroidRuntime(26991): at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:608)
E/AndroidRuntime(26991): at es.antonborri.home_widget.HomeWidgetPlugin.onDetachedFromActivity(HomeWidgetPlugin.kt:150)
E/AndroidRuntime(26991): at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.detachFromActivity(FlutterEngineConnectionRegistry.java:389)
E/AndroidRuntime(26991): at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onDetach(FlutterActivityAndFragmentDelegate.java:560)
E/AndroidRuntime(26991): at io.flutter.embedding.android.FlutterActivity.release(FlutterActivity.java:595)
E/AndroidRuntime(26991): at io.flutter.embedding.android.FlutterActivity.onDestroy(FlutterActivity.java:616)
E/AndroidRuntime(26991): at android.app.Activity.performDestroy(Activity.java:6881)
E/AndroidRuntime(26991): at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1153)
E/AndroidRuntime(26991): at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4190)
E/AndroidRuntime(26991): ... 9 more
[✓] Flutter (Channel master, 2.2.0-11.0.pre.69, on macOS 11.2.3 20D91
darwin-x64, locale en-VN)
• Flutter version 2.2.0-11.0.pre.69 at /Users/huytd/flutter
• Framework revision 02efffc134 (5 days ago), 2021-04-10 03:49:01 -0400
• Engine revision 8863afff16
• Dart version 2.13.0 (build 2.13.0-222.0.dev)[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
• Android SDK at /Users/huytd/android-sdk
• Platform android-30, build-tools 30.0.2
• ANDROID_HOME = /Users/huytd/android-sdk
• Java binary at: /Applications/Android
Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
1.8.0_242-release-1644-b3-6915495)
• All Android licenses accepted.[✓] Xcode - develop for iOS and macOS
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 12.4, Build version 12D4e
• CocoaPods version 1.10.1[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome[✓] Android Studio (version 4.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build
1.8.0_242-release-1644-b3-6915495)[✓] Connected device (1 available)
• Chrome (web) • chrome • web-javascript • Google Chrome 89.0.4389.128• No issues found!
Improve the hints and error messages of the example app indicating that the appGroupId needs to be set on iOS.
The sample code is not working properly on ios.
Hi,
when I try to register a background callback to register clicks on a home widget, I get a ClassCastException in HomeWidgetPlugin.kt:
E/MethodChannel#home_widget(11269): Failed to handle method call
E/MethodChannel#home_widget(11269): java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
E/MethodChannel#home_widget(11269): at es.antonborri.home_widget.HomeWidgetPlugin.onMethodCall(HomeWidgetPlugin.kt:99)
E/MethodChannel#home_widget(11269): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/MethodChannel#home_widget(11269): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/MethodChannel#home_widget(11269): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/MethodChannel#home_widget(11269): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#home_widget(11269): at android.os.MessageQueue.next(MessageQueue.java:326)
E/MethodChannel#home_widget(11269): at android.os.Looper.loop(Looper.java:160)
E/MethodChannel#home_widget(11269): at android.app.ActivityThread.main(ActivityThread.java:6669)
E/MethodChannel#home_widget(11269): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#home_widget(11269): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/MethodChannel#home_widget(11269): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
E/flutter (11269): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: PlatformException(error, java.lang.Integer cannot be cast to java.lang.Long, null, java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
E/flutter (11269): at es.antonborri.home_widget.HomeWidgetPlugin.onMethodCall(HomeWidgetPlugin.kt:99)
E/flutter (11269): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/flutter (11269): at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/flutter (11269): at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/flutter (11269): at android.os.MessageQueue.nativePollOnce(Native Method)
E/flutter (11269): at android.os.MessageQueue.next(MessageQueue.java:326)
E/flutter (11269): at android.os.Looper.loop(Looper.java:160)
E/flutter (11269): at android.app.ActivityThread.main(ActivityThread.java:6669)
E/flutter (11269): at java.lang.reflect.Method.invoke(Native Method)
E/flutter (11269): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
E/flutter (11269): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
E/flutter (11269): )
E/flutter (11269): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:581:7)
E/flutter (11269): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:158:18)
E/flutter (11269):
E/flutter (11269):
When I try clicking on a part of a home widget I get an error:
E/HomeWidgetBackgroundService(11269): No callbackHandle saved. Did you call HomeWidgetPlugin.registerBackgroundCallback?
And then the app crashes.
I think I found a solution for this problem.
If I change
val dispatcher = (call.arguments as Iterable<*>).toList()[0].toString().toLong()
val callback = (call.arguments as Iterable<*>).toList()[1].toString().toLong()
The issue with casting is gone and app registers a background callback and everything works as expected.
Best regards,
Aljosa
I copied files in kotlin/es/antonborri/home_widget_example and launched main.dart but it says Unresolved reference: R
I think that this line makes error.
val views = RemoteViews(context.packageName, R.layout.example_layout).apply {
Do I have to import R to my project?
Hello,
I applied this library success,
I add more feature when using this.
I did not found any document details the method like setOnClickListener()
(or setTextViewText()
) to apply (Even Ctril+Space
does not help me also)
So how I implemented a clicked button success?
Please help me indicate that?
[✓] Flutter (Channel stable, 1.22.3, on macOS 11.0.1 20B29, locale en-VN)
• Flutter version 1.22.3 at /Users/huytd/flutter
• Framework revision 8874f21e79 (2 weeks ago), 2020-10-29 14:14:35 -0700
• Engine revision a1440ca392
• Dart version 2.10.3[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
• Android SDK at /Users/huytd/android-sdk
• Platform android-30, build-tools 30.0.2
• ANDROID_HOME = /Users/huytd/android-sdk
• Java binary at: /Applications/Android
Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
1.8.0_242-release-1644-b3-6915495)
• All Android licenses accepted.[✓] Xcode - develop for iOS and macOS (Xcode 12.2)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 12.2, Build version 12B45b
• CocoaPods version 1.10.0[!] Android Studio (version 4.1)
• Android Studio at /Applications/Android Studio.app/Contents
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
• Java version OpenJDK Runtime Environment (build
1.8.0_242-release-1644-b3-6915495)[✓] Connected device (1 available)
• Android SDK built for x86 (mobile) • emulator-5554 • android-x86 • Android
7.1.1 (API 25) (emulator)
initiallyLaunchedFromHomeWidget() function never returns result if the launch was not from a widget.
Please change this
if(initialUrl != nil) {
result(initialUrl?.absoluteString)
}
to this
result(initialUrl?.absoluteString)
Hello bro,
I can reload home widget for platform Android,
while platform iOs is not.
I can replace content "..." by other content in platform Android, while can not in platform iOs.
Please tell me what I need to do more.
Code sample :
I used this in main widget as guide told me.
@override
void initState() {
super.initState();
// HOME_SCREEN_WIDGET_ID : nct_home_widget
HomeWidget.setAppGroupId(Constants.HOME_SCREEN_WIDGET_ID);
}
I'm using these code for update data (it works for platform Android)
iOs files structure: (HomeWidgetExample created as Widget Extension in Xcode)
HomeWidgetExample.swift
//
// widget.swift
// widget
import WidgetKit
import SwiftUI
import Intents
private let widgetGroupId = "nct_home_widget"
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> ExampleEntry {
ExampleEntry(date: Date(), title: "Placeholder Title", message: "Placeholder Message")
}
func getSnapshot(in context: Context, completion: @escaping (ExampleEntry) -> ()) {
let data = UserDefaults.init(suiteName:widgetGroupId)
let entry = ExampleEntry(date: Date(), title: data?.string(forKey: "title") ?? "No Title Set", message: data?.string(forKey: "message") ?? "No Message Set")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
getSnapshot(in: context) { (entry) in
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
}
}
struct ExampleEntry: TimelineEntry {
let date: Date
let title: String
let message: String
}
struct HomeWidgetExampleEntryView : View {
var entry: Provider.Entry
let data = UserDefaults.init(suiteName:widgetGroupId)
var body: some View {
VStack.init(alignment: .leading, spacing: /*@START_MENU_TOKEN@*/nil/*@END_MENU_TOKEN@*/, content: {
Text(entry.title).bold().font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/)
Text(entry.message).font(.body)
}
)}
}
@main
struct HomeWidgetExample: Widget {
let kind: String = "nct_home_widget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
HomeWidgetExampleEntryView(entry: entry)
}
.configurationDisplayName("nct_home_widget")
.description("nct_home_widget")
}
}
struct HomeWidgetExample_Previews: PreviewProvider {
static var previews: some View {
HomeWidgetExampleEntryView(entry: ExampleEntry(date: Date(), title: "nct_home_widget", message: "nct_home_widget"))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
Fatal Exception: java.lang.RuntimeException: Unable to create service es.antonborri.home_widget.HomeWidgetBackgroundService: java.lang.NullPointerException: Attempt to read from field 'java.lang.String io.flutter.view.FlutterCallbackInformation.callbackLibraryPath' on a null object reference
at android.app.ActivityThread.handleCreateService(ActivityThread.java:4673)
at android.app.ActivityThread.access$1700(ActivityThread.java:301)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2196)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8653)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Hi, first of all thanks for your package!
When working with home screen widgets on Android, I realized that the background intent (HomeWidgetBackgroundIntent.getBroadcast) sometimes suddenly gets into a delayed state. I thought I implemented something wrong, but after checking, it seems to also happen with the sample from the package (change title on click).
I tested on emulator (API 29) and also on my phone (API 30), it shows the same behaviour.
If it enters the delayed state, the next update happens >10 seconds after a click, sometimes earlier, or sometimes when you click on the widget to open the app (HomeWidgetLaunchIntent.getActivity).
I tried to find something in the logs but without any success.
So I was wondering if you maybe know, what is causing the delays (and maybe how to avoid them) ?
I tried this but doesn't work:
Workmanager.registerPeriodicTask('1', 'widgetBackgroundUpdate', frequency: Duration(seconds: 1));
get this error:
Interval duration lesser than minimum allowed value; Changed to 900000
. That's the 15 default minutes. Is not possible to reduce this limit anyhow?
My app shows how much money you earn/pay by second so I need a widget to show also same info without opening the app (more info: https://play.google.com/store/apps/details?id=com.drodriguez.profits)
i have an error when i click the arrow back on android and then i open the app with the home screen widget.
[ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type 'bool' is not a subtype of type 'String?' in type cast
E/flutter (14900): #0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:158:41)
E/flutter (14900): .
this is the erro, i try to check this, but i can't resolved, it just happen when you go back and then u click the widget to open the app again cause android destroy the app, and then idk why cannot rebuild well.
Destroying service.
D/FlutterLocationService(14900): Creating service.
D/FlutterLocationService(14900): Binding to location service.
After following set up instructions and comparing with example app, I'm not sure what the issue might be.
In my AndroidManifex.xml
I have:
<receiver android:name="HomeWidgetExampleProvider" >
<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>
And in my android/app/src/main/kotlin/com/someName/app/anotherName/HomeWidgetExampleProvider.kt
I have the same code from the example project.
I did add Kotlin support to my Flutter app which was originally configured as Java. After sorting our some build issues, MainActivity.kt
path seems to be working, but HomeWidgetExampleProvider.kt
in the same directory is not?
Any ideas?
EDIT: I forgot to mention, the example widget will build fine and has the time when initially created, but this error is still thrown and also thrown on subsequent updates from Workmanager periodic task. Time will remain the same as when created.
Hi,
At the moment I am registering a workmanager periodic task in my app's initstate to update my widget in the background. This works but it is registering & running the task even though there may be no widgets on the home screen for my app. I'm not sure if there is a way to know when the user adds a widget to the home screen so the workmanager task can be registered at that moment? Or is there another point I should be registering the workmanager task? Your example app uses a button, but that wouldn't work in this instance. So the outcome I'd like is to register the workmanager periodic task when a widget is added.
Thankyou!
Right now Platform name needs to be the same for iOS and Android. Add a option to add separate names to be more flexible on naming the Widgets however it suits the platform best
All dependencies are migrated to null safety. So we should migrate this package to null safety.
I see that the registerBackgroundCallback
feature released in 0.1.2 version is not available in iOS. Is there a limitation in iOS platform?
I have seen that widgets click in iOS can just open app using DeepLink (like already implemented in that plugin) but I am not sure about it.
I appreciate any answer.
We have tried to use a custom Font called Rubik:
https://fonts.google.com/specimen/Rubik
Neither by passing the font to the widget itself, nor with attaching a shared resource from flutter to the native android part. Is this a known limit (of the package/ general) for android as the home widget always inherits the system font?
Hi, I want update widget showing data from a http get request every hour.
Where should I place this code? in flutter or somewhere?
@ABausG When we expect the click from widget to app?
Originally posted by @vishaldhaduk4495 in #6 (comment)
Hello! I am having problems with the library. I tried to integrate the example from the library into my project, but I got the following problem:
E/AndroidRuntime(27577): java.lang.RuntimeException: Unable to instantiate receiver com.vadimrm.clastere.HomeWidgetProvider: java.lang.ClassNotFoundException: Didn't find class "com.vadimrm.clastere.HomeWidgetProvider" on path: DexPathList[[zip file "/data/app/~~88u_Wa5GQ7Svqajbbr4qdw==/com.vadimrm.clastere-0pEzhjkNxr5w8bTWaCZNsg==/base.apk"],nativeLibraryDirectories=[/data/app/~~88u_Wa5GQ7Svqajbbr4qdw==/com.vadimrm.clastere-0pEzhjkNxr5w8bTWaCZNsg==/lib/x86, /data/app/~~88u_Wa5GQ7Svqajbbr4qdw==/com.vadimrm.clastere-0pEzhjkNxr5w8bTWaCZNsg==/base.apk!/lib/x86, /system/lib, /system_ext/lib]]
E/AndroidRuntime(27577): at android.app.ActivityThread.handleReceiver(ActivityThread.java:4018)
E/AndroidRuntime(27577): at android.app.ActivityThread.access$1400(ActivityThread.java:237)
E/AndroidRuntime(27577): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1924)
E/AndroidRuntime(27577): at android.os.Handler.dispatchMessage(Handler.java:106)
E/AndroidRuntime(27577): at android.os.Looper.loop(Looper.java:223)
E/AndroidRuntime(27577): at android.app.ActivityThread.main(ActivityThread.java:7656)
E/AndroidRuntime(27577): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(27577): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
E/AndroidRuntime(27577): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
E/AndroidRuntime(27577): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.vadimrm.clastere.HomeWidgetProvider" on path: DexPathList[[zip file "/data/app/~~88u_Wa5GQ7Svqajbbr4qdw==/com.vadimrm.clastere-0pEzhjkNxr5w8bTWaCZNsg==/base.apk"],nativeLibraryDirectories=[/data/app/~~88u_Wa5GQ7Svqajbbr4qdw==/com.vadimrm.clastere-0pEzhjkNxr5w8bTWaCZNsg==/lib/x86, /data/app/~~88u_Wa5GQ7Svqajbbr4qdw==/com.vadimrm.clastere-0pEzhjkNxr5w8bTWaCZNsg==/base.apk!/lib/x86, /system/lib, /system_ext/lib]]
E/AndroidRuntime(27577): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:207)
E/AndroidRuntime(27577): at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
E/AndroidRuntime(27577): at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
E/AndroidRuntime(27577): at android.app.AppComponentFactory.instantiateReceiver(AppComponentFactory.java:110)
E/AndroidRuntime(27577): at androidx.core.app.CoreComponentFactory.instantiateReceiver(CoreComponentFactory.java:60)
E/AndroidRuntime(27577): at android.app.ActivityThread.handleReceiver(ActivityThread.java:4011)
E/AndroidRuntime(27577): ... 8 more
I/Process (27577): Sending signal. PID: 27577 SIG: 9
android/build.gradle
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.google.gms:google-services:4.3.5'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.0'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
app/build.gradle
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 29
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
applicationId "com.vadimrm.clastere"
minSdkVersion 23
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
buildTypes {
release {
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
project structure:
Android manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.vadimrm.clastere">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk
android:minSdkVersion="8" />
<application
android:label="Clastere"
android:icon="@mipmap/ic_launcher"
android:networkSecurityConfig="@xml/network_security_config">
<provider
android:name="sk.fourq.otaupdate.OtaUpdateFileProvider"
android:authorities="${applicationId}.ota_update_provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="secret"/>
<meta-data
android:name="com.google.android.gms.ads.AD_MANAGER_APP"
android:value="true"/>
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"
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">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<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>
<receiver android:name="HomeWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget" />
</receiver>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
HomeWidgetProvider.kt
package com.vadimrm.clastere
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import android.widget.RemoteViews
import es.antonborri.home_widget.HomeWidgetBackgroundIntent
import es.antonborri.home_widget.HomeWidgetLaunchIntent
import es.antonborri.home_widget.HomeWidgetProvider
class HomeWidgetExampleProvider : HomeWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
appWidgetIds.forEach { widgetId ->
val views = RemoteViews(context.packageName, R.layout.widget).apply {
// Open App on Widget Click
val pendingIntent = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java)
setOnClickPendingIntent(R.id.widget_container, pendingIntent)
// Swap Title Text by calling Dart Code in the Background
setTextViewText(R.id.widget_title, widgetData.getString("title", null)
?: "No Title Set")
val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(
context,
Uri.parse("homeWidgetExample://titleClicked")
)
setOnClickPendingIntent(R.id.widget_title, backgroundIntent)
val message = widgetData.getString("message", null)
setTextViewText(R.id.widget_message, message
?: "No Message Set")
// Detect App opened via Click inside Flutter
val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homeWidgetExample://message?message=$message"))
setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData)
}
appWidgetManager.updateAppWidget(widgetId, views)
}
}
}
I am new to android development. I would really appreciate your help
Is there any way or example for update widget data on interval when app is killed.
Could you please add an example of a configurable widget on Android, using flutter activity to configure the widget ?
I see code: name: 'HomeWidgetExampleProvider', iOSName: 'HomeWidgetExample');
I don't see about clase HomeWidgetExampleProvider
Where are this?
Thank you for support
As per Flutter engine implementation UIApplication:open
is suppose to return false
if link is not handled by the plugin.
But in home_widget plugin it is always returning true
and this blocks plugins like uni_links
to get the URL.
home_widget/ios/Classes/SwiftHomeWidgetPlugin.swift
Lines 134 to 139 in 6559612
I have a fix in #46 that properly returns the flag.
I have an app with 2 pages: Homepage and Quiz. When the user presses the widget on homescreen, the app opens with first screen Homepage and then the code from _checkForWidgetLaunch
void didChangeDependencies() {
Debug.d("Homepage didChangeDependencies");
super.didChangeDependencies();
//once the app is started from the widget, this is triggered ad infinitum
// _checkForWidgetLaunch();
// HomeWidget.widgetClicked.listen(_launchedFromWidget);
}
calls _launchedFromWidget
and navigates to Quiz (Navigator.push
).
When close Quiz/back button, the Homepage.didChangeDependencies() is called and the Quiz is stared again! This is an infinite cycle.
I managed to fix this by adding to Homepage.initState()
// //https://stackoverflow.com/questions/49466556/flutter-run-method-on-widget-build-complete
WidgetsBinding.instance.addPostFrameCallback((_) => _afterInit());
and in afterInit call the code
_afterInit() async {
_checkForWidgetLaunch();
HomeWidget.widgetClicked.listen(_launchedFromWidget);
}
I hope this helps other people as well. Maybe consider testing and updating documentation?
Thank you very much for your great effort, it's truly a wonderful and incredibly useful component.
import 'package:home_widget/home_widget_callback_dispatcher.dart';
Show error:
Target of URI doesn't exist: 'package:home_widget/home_widget_callback_dispatcher.dart'.
Undefined name 'HomeWidget'.
But plugin was added, flutter get
was called many times.
home_widget: ^0.1.5
Hi, I am new to flutter. I am having an issue with configuring on Android.
PlatformException (PlatformException(-3, No Widget found with Name HomeWidgetExampleProvider. Argument 'name' must be the same as your AppWidgetProvider you wish to update, java.lang.ClassNotFoundException: com.ajay.owadio.HomeWidgetExampleProvider at java.lang.Class.classForName(Native Method) at java.lang.Class.forName(Class.java:454) at java.lang.Class.forName(Class.java:379) at es.antonborri.home_widget.HomeWidgetPlugin.onMethodCall(HomeWidgetPlugin.kt:64) at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233) at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85) at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:692) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:335) at android.os.Looper.loop(Looper.java:183) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Caused by: java.lang.ClassNotFoundException: Didn't find class "com.ajay.owadio.HomeWidgetExampleProvider" on path: DexPathList[[zip file "/data/app/~~ofh_quxw5tSewumlGyuJXQ==/com.ajay.owadio-mgvxU_hG_RGKA8SOFcf_Gg==/base.apk"],nativeLibraryDirectories=[/data/app/~~ofh_quxw5tSewumlGyuJXQ==/com.ajay.owadio-mgvxU_hG_RGKA8SOFcf_Gg==/lib/x86, /data/app/~~ofh_quxw5tSewumlGyuJXQ==/com.ajay.owadio-mgvxU_hG_RGKA8SOFcf_Gg==/base.apk!/lib/x86, /system/lib, /system_ext/lib]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:207) at java.lang.ClassLoader.loadClass(ClassLoader.java:379) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) ... 14 more , null))
I am unable to solve the issue
I found it was really hard to make this image be round radius!!
any suggestions?
package cn.xx.xx
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import android.widget.RemoteViews
import cn.manaai.daybreak.R
import es.antonborri.home_widget.HomeWidgetBackgroundIntent
import es.antonborri.home_widget.HomeWidgetLaunchIntent
import es.antonborri.home_widget.HomeWidgetProvider
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import com.bumptech.glide.load.resource.bitmap.TransformationUtils
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
class HomeWidgetGlanceProvider : HomeWidgetProvider(), AppCompatActivity {
// this load a todo widget, showing todos here
// so the layout here is different.
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
appWidgetIds.forEach { widgetId ->
val views = RemoteViews(context.packageName, R.layout.glance_app_widget).apply {
// Open App on Widget Click
val pendingIntent = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java)
setOnClickPendingIntent(R.id.widget_container, pendingIntent)
// Swap Title Text by calling Dart Code in the Background
setTextViewText(R.id.nickname, widgetData.getString("title", null)
?: "No Title Set")
val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(
context,
Uri.parse("homeWidgetExample://titleClicked2")
)
setOnClickPendingIntent(R.id.nickname, backgroundIntent)
val message = widgetData.getString("message", null)
setTextViewText(R.id.todonum, message
?: "12")
// Detect App opened via Click inside Flutter
val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java,
Uri.parse("homeWidgetExample://message?message=$message"))
setOnClickPendingIntent(R.id.todonum, pendingIntentWithData)
var avatar = findViewById(R.id.avatar) as ImageView;
// avatar
Glide.with(this).load("http://p15.qhimg.com/bdm/720_444_0/t01b12dfd7f42342197.jpg")
.apply(RequestOptions.bitmapTransform(RoundedCorners(20)))
// .circleCrop()
.into(avatar)
}
appWidgetManager.updateAppWidget(widgetId, views)
}
}
}
I have been trying to figure out how to add a ListView with programmatically updatable TextViews within the ListView but I am unsure of how to accomplish this. Does anyone have any suggestions?
Thank you
Hey!
Sorry for the question, but how can I debug or test this? For example, I am writing code on the flutter side and run the app, but I want to debug the widget and see the information coming to the widget and debug it. How can I achieve this? I have tried running the project on XCode but nothing happens
I have to say, the code in example
can't compile at all, I found that
environment:
sdk: ">=2.12.0 <3.0.0"
and I have goggled but found there are only one useful tutorial about using home_widget
https://medium.com/@ashishgarg1998/how-to-create-home-screen-app-widgets-in-flutter-ce3458f3638e
can you give more example for using home_widget
?
There is no way to refresh data from widget using button.
Hi, After your #53 update, I have just started trying to get my app working on iOS. I had done quite a bit of work on it, so I'm not sure if this is still related, but now I am getting this error:
An error was encountered processing the command (domain=IXErrorDomain, code=2):
Failed to create plugin placeholder for /app path/build/ios/iphonesimulator/Runner.app/PlugIns/HomeWidgetExtension.appex
Failed to create promise.
Underlying error (domain=IXErrorDomain, code=2):
Failed to set placeholder attributes {app path & name}.HomeWidget
Failed to create promise.
I have a fully working IntentTimelineProvider that allows me to choose content for the widget to show from inside my flutter application. This works great.
The only issue is I can no longer seem to update the widget using HomeWidget.update
am I missing something or is this a limitation?
In IOS 13 and later, to be able to use background refreshing of the app, the BGTaskScheduler should be used and the UIApplication does not work.
https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/using_background_tasks_to_update_your_app
Is it possible to update an ImageView in the widget from Flutter assets? I have a weather app and looking to update the weather forecast icon on the widget, but I'm struggling to figure out how to do it. I can update a resource file, but I'd prefer not to have to have two copies. I'm only a beginner, so using this to learn. Any help would be appreciated. Thanks.
Fairly new to all of this. I had Android working perfectly and tried to add an ios widget. I'm using workmanager to try to update the widget in the back ground. However I am getting this error.
The error also occurs on the example app.
For me this error occurs when I try to get data from an api using the http package.
[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: MissingPluginException(No implementation found for method registerBackgroundCallback on channel home_widget)
#0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:156:7)
[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: PlatformException(Error 8, kCLErrorDomain, The operation couldn’t be completed. (kCLErrorDomain error 8.), null)
#0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:597:7)
#1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:158:18)
#2 LocalGeocoding.findAddressesFromQuery (package:geocoder/services/local.dart:18:28)
#3 _WeatherAppState.getLatLngFromLocation (package:weatherapp/main.dart:614:21)
As I'm new to this - please let me know what you need.
In HomeWidgetPlugin.kt#L79 a call to result.success
is missing.
So when you await updateWidget like below it doesn't finish.
await HomeWidget.updateWidget(
name: 'WidgetProvider',
androidName: 'WidgetProvider',
iOSName: 'WidgetProvider',
);
I haven't personally tested this. If you prefer, I can test and send a PR.
Please consider updating the documentation to remove flutter_workmanager
as it looks unmaintained and it straight up crashes on the emulator S as per fluttercommunity/flutter_workmanager#352.
An easy replacement could be https://pub.dev/packages/android_alarm_manager_plus.
Hey,
is there a way to setup pendingIntentTemplate with background click. If I use
"HomeWidgetBackgroundIntent.getBroadcast(context)"
for setPendingIntentTemplate, then data sent with setOnClickFillInIntent is empty
Does this handle multiple instances of same widget?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.