Flutter Package for Easier Creation of Home Screen Widgets

Related tags

Widgets home_widget
Overview

Home Widget

Pub likes popularity pub points Build

HomeWidget is a Plugin to make it easier to create HomeScreen Widgets on Android and iOS. HomeWidget does not allow writing Widgets with Flutter itself. It still requires writing the Widgets with native code. However, it provides a unified Interface for sending data, retrieving data and updating the Widgets

iOS  Android

Platform Setup

In order to work correctly there needs to be some platform specific setup. Check below on how to add support for Android and iOS

Android

Create Widget Layout inside android/app/res/layout

Create Widget Configuration into android/app/res/xml

">
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>

Add WidgetReceiver to AndroidManifest

">
<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>

Write your 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

import es.antonborri.home_widget.HomeWidgetPlugin
...
HomeWidgetPlugin.getData(context)

which will give you access to the same SharedPreferences

More Information

For more Information on how to create and configure Android Widgets checkout (https://developer.android.com/guide/topics/appwidgets)[this guide] on the Android Developers Page.

iOS

Add a Widget to your App in Xcode

Add a widget extension by going File > Target > Widget Extension

Widget Extension

Add GroupId

You need to add a groupId to the App and the Widget Extension

Note: in order to add groupIds you need a paid Apple Developer Account

Go to your Apple Developer Account and add a new group Add this group to you Runner and the Widget Extension inside XCode Signing & Capabilities > App Groups > +

Build Targets

(To swap between your App, and the Extension change the Target)

Sync CFBundleVersion (optional)

This step is optional, this will sync the widget extension build version with your app version, so you don't get warnings of mismatch version from App Store Connect when uploading your app.

Build Phases

In your Runner (app) target go to Build Phases > + > New Run Script Phase and add the following script:

generatedPath="$SRCROOT/Flutter/Generated.xcconfig"
versionNumber=$(grep FLUTTER_BUILD_NAME $generatedPath | cut -d '=' -f2)
buildNumber=$(grep FLUTTER_BUILD_NUMBER $generatedPath | cut -d '=' -f2)
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$SRCROOT/HomeExampleWidget/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $versionNumber" "$SRCROOT/HomeExampleWidget/Info.plist"

Replace HomeExampleWidget with the name of the widget extension folder that you have created.

Write your Widget

Check the Example App for an Implementation of a Widget A more detailed overview on how to write Widgets for iOS 14 can fbe found on the Apple Developer documentation. In order to access the Data send with Flutter can be access with

let data = UserDefaults.init(suiteName:"YOUR_GROUP_ID")

Usage

Setup

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

Save Data

In order to save Data call HomeWidget.saveWidgetData ('id', data)

Update a Widget

In order to force a reload of the HomeScreenWidget you need to call

HomeWidget.updateWidget(
    name: 'HomeWidgetExampleProvider',
    androidName: 'HomeWidgetExampleProvider',
    iOSName: 'HomeWidgetExample',
);

The name for Android will be chosen by checking androidName if that was not provided it will fallback to name. This Name needs to be equal to the Classname of the 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

Retrieve Data

To retrieve the current Data saved in the Widget call HomeWidget.getWidgetData ('id', defaultValue: data)

Background Update

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.

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:

WorkmanagerPlugin.setPluginRegistrantCallback { registry in
    GeneratedPluginRegistrant.register(with: registry)
}

to AppDelegate.swift

Clicking

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.

In order for these methods to work you need to follow these steps:

iOS

Add .widgetUrl to your 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

Android

Add an IntentFilter to the Activity Section in your AndroidManifest

">

  
    
   

  

In your WidgetProvider add a PendingIntent to your View using HomeWidgetLaunchIntent.getActivity

val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity(
        context,
        MainActivity::class.java,
        Uri.parse("homeWidgetExample://message?message=$message"))
setOnClickPendingIntent(R.id.widget_message, pendingIntentWithData)

Background Click

Android allows interactive elements in HomeScreenWidgets. This allows to for example add a refresh button on a widget. With home_widget you can use this by following these steps:

Android/Native Part

  1. Add the necessary Receiver and Service to you AndroidManifest.xml file
    ">
    
         
        
          
            
           
        
          
    
         
    
         
    
  2. Add a HomeWidgetBackgroundIntent.getBroadcast PendingIntent to the View you want to add a click listener to
    val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(
        context,
        Uri.parse("homeWidgetExample://titleClicked")
    )
    setOnClickPendingIntent(R.id.widget_title, backgroundIntent)

Dart

  1. Write a static function that takes a Uri as an argument. This will get called when a user clicks on the View
    void backgroundCallback(Uri data) {
      // do something with data
      ...
    }
  2. Register the callback function by calling
    HomeWidget.registerBackgroundCallback(backgroundCallback);
Comments
  • Can reload home widget for platform Android, while platform iOs is not

    Can reload home widget for platform Android, while platform iOs is not

    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. Screen Shot 2020-11-19 at 16 48 22

    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) Screen Shot 2020-11-19 at 16 12 48 Screen Shot 2020-11-19 at 16 12 41

    iOs files structure: (HomeWidgetExample created as Widget Extension in Xcode) Screen Shot 2020-11-19 at 16 47 15

    *.entitlements Screen Shot 2020-11-19 at 16 14 15

    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))
        }
    }
    
    iOS 
    opened by huytower 15
  • Unresolved reference: R

    Unresolved reference: R

    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?

    Android 
    opened by tomriddle7 12
  • MissingPluginException(No implementation found for method registerBackgroundCallback on channel home_widget)

    MissingPluginException(No implementation found for method registerBackgroundCallback on channel home_widget)

    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.

    opened by roly151 9
  • Unable to instantiate receiver

    Unable to instantiate receiver

    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: image 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

    Android 
    opened by vadim-rm 9
  • Add click button on widget

    Add click button on widget

    Hello,

    I applied this library success, I add more feature when using this.

    • Show title & message (done)
    • A button for integrate : Play button (doing) Screen Shot 2020-11-16 at 14 17 26

    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?

    Code lines : Screen Shot 2020-11-16 at 14 17 54 Screen Shot 2020-11-16 at 14 18 11

    [✓] 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)

    Android 
    opened by huytower 7
  • 'package:home_widget/home_widget_callback_dispatcher.dart' not found

    'package:home_widget/home_widget_callback_dispatcher.dart' not found

    I am trying to use the backgroundCallback to refresh my widget by pressing an image on the widget. It works fine on debug mode, however when I build apk or run flutter run --release --verbose I get the error below (well in apk I can't see the error but it does not work either).

    I get this error after tapping the image with the callback URI:

    [ +9 ms] E/flutter (14277): [ERROR:flutter/shell/common/shell.cc(88)] Dart Error: Dart_LookupLibrary: library 'package:home_widget/home_widget_callback_dispatcher.dart' not found. [ ] E/flutter (14277): [ERROR:flutter/runtime/dart_isolate.cc(668)] Could not resolve main entrypoint function. [ ] E/flutter (14277): [ERROR:flutter/runtime/dart_isolate.cc(167)] Could not run the run main Dart entrypoint. [ ] E/flutter (14277): [ERROR:flutter/runtime/runtime_controller.cc(386)] Could not create root isolate. [ ] E/flutter (14277): [ERROR:flutter/shell/common/shell.cc(605)] Could not launch engine with configuration. [ +28 ms] W/FlutterJNI(14277): FlutterJNI.loadLibrary called more than once [ ] W/FlutterJNI(14277): FlutterJNI.prefetchDefaultFontManager called more than once [ ] W/FlutterJNI(14277): FlutterJNI.init called more than once [ +8 ms] E/flutter (14277): [ERROR:flutter/runtime/dart_isolate.cc(668)] Could not resolve main entrypoint function. [ ] E/flutter (14277): [ERROR:flutter/runtime/dart_isolate.cc(167)] Could not run the run main Dart entrypoint. [ ] E/flutter (14277): [ERROR:flutter/runtime/runtime_controller.cc(386)] Could not create root isolate. [ ] E/flutter (14277): [ERROR:flutter/shell/common/shell.cc(605)] Could not launch engine with configuration.

    That makes no sense to me. What confuses me is that it is working fine in Debug. You can see here that the file is in my package beside the other one.

    Doctor summary:

    [✓] Flutter (Channel master, 3.4.0-19.0.pre.35, on Microsoft Windows [Version 10.0.22000.856], locale en-CA) [✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1) [✓] Chrome - develop for the web [✗] Visual Studio - develop for Windows ✗ Visual Studio not installed; this is necessary for Windows development. Download at https://visualstudio.microsoft.com/downloads/. Please install the "Desktop development with C++" workload, including all of its default components [✓] Android Studio (version 2021.2) [✓] VS Code, 64-bit edition (version 1.67.2) [✓] Connected device (4 available) [✓] HTTP Host Availability

    opened by saad197 5
  • iOS widget doesn't update

    iOS widget doesn't update

    Hello, my iOS widget won't give me an error (the function returns true), and it won't update the widget either.

    I set my group id as group.salamlabs.salamapp.HomeWidget and it is configured correctly.

    AppDelegate.swift

    import UIKit
    import Flutter
    import workmanager
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
          UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*15))
           //return true
     
    //   if #available(iOS 10.0, *) {
    //     UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
    //   }
          GeneratedPluginRegistrant.register(with: self)
          UNUserNotificationCenter.current().delegate = self
    WorkmanagerPlugin.setPluginRegistrantCallback { registry in
        GeneratedPluginRegistrant.register(with: registry)
    }
    
    
    
                 return super.application(application, didFinishLaunchingWithOptions: launchOptions)
          }
    
          override func userNotificationCenter(
                  _ center: UNUserNotificationCenter,
                  willPresent notification: UNNotification,
                  withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
                   completionHandler(.alert) // shows banner even if app is in foreground
               }
    
    
    }
    

    HomeWidget.swift

    //
    //  HomeWidget.swift
    //  HomeWidget
    //
    //  Created by Ismail Fateen on 11/06/2022.
    //
    
    import WidgetKit
    import SwiftUI
    
    private let widgetGroupId = "group.salamlabs.salamapp.HomeWidget"
    
    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: nil, content: {
                Text(entry.title).bold().font(.title)
                Text(entry.message)
                    .font(.body)
                    .widgetURL(URL(string: "homeWidgetExample://message?message=\(entry.message)&homeWidget"))
            }
            )
        }
    }
    
    @main
    struct HomeWidgetExample: Widget {
        let kind: String = "HomeWidget"
        
        var body: some WidgetConfiguration {
            StaticConfiguration(kind: kind, provider: Provider()) { entry in
                HomeWidgetExampleEntryView(entry: entry)
            }
            .configurationDisplayName("My Widget")
            .description("This is an example widget.")
        }
    }
    
    struct HomeWidgetExample_Previews: PreviewProvider {
        static var previews: some View {
            HomeWidgetExampleEntryView(entry: ExampleEntry(date: Date(), title: "Example Title", message: "Example Message"))
                .previewContext(WidgetPreviewContext(family: .systemSmall))
        }
    }
    

    Code that “updates” the widget:

                      await HomeWidget.setAppGroupId(
                          "group.salamlabs.salamapp.HomeWidget");
                      await HomeWidget.saveWidgetData("title", "yes");
                      await HomeWidget.saveWidgetData("message", "no");
                      var result = await HomeWidget.updateWidget(
                          iOSName: "HomeWidget", name: "HomeWidget");
                      print(result.toString()); // prints `true`, doesn't update
    

    flutter doctor -v

    [✓] Flutter (Channel stable, 2.10.5, on macOS 13.0 22A5266r darwin-arm, locale
        en-EG)
        • Flutter version 2.10.5 at /opt/flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 5464c5bac7 (8 weeks ago), 2022-04-18 09:55:37 -0700
        • Engine revision 57d3bac3dd
        • Dart version 2.16.2
        • DevTools version 2.9.2
    
    [✓] Android toolchain - develop for Android devices (Android SDK version
        32.1.0-rc1)
        • Android SDK at /Users/ismailfateen/Library/Android/sdk
        • Platform android-32, build-tools 32.1.0-rc1
        • Java binary at: /Applications/Android
          Studio.app/Contents/jre/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build
          11.0.12+0-b1504.28-7817840)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 13.4.1)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • CocoaPods version 1.11.3
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 2021.2)
        • 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
          11.0.12+0-b1504.28-7817840)
    
    [✓] IntelliJ IDEA Community Edition (version 2022.1.1)
        • IntelliJ at /Applications/IntelliJ IDEA CE.app
        • 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
    
    [✓] VS Code (version 1.68.0)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.42.0
    
    [✓] Connected device (2 available)
        • iPhone SE (3rd generation) (mobile) • 393BE168-DDAA-4F01-9ED8-63624660D2FD
          • ios            • com.apple.CoreSimulator.SimRuntime.iOS-15-5 (simulator)
        • Chrome (web)                        • chrome
          • web-javascript • Google Chrome 102.0.5005.61
    
    [✓] HTTP Host Availability
        • All required HTTP hosts are available
    
    • No issues found!
    
    opened by ismailfateen 5
  • Multiple Widgets

    Multiple 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"/>

    opened by roly151 5
  • [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type 'bool' is not a subtype of type 'String?' in type cast

    [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type 'bool' is not a subtype of type 'String?' in type cast

    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.

    bug 
    opened by chame10 5
  • new compilation error in flutter 3.0.0

    new compilation error in flutter 3.0.0

    e: D:\flutter\flutter\.pub-cache\hosted\pub.dartlang.org\home_widget-0.1.5\android\src\main\kotlin\es\antonborri\home_widget\HomeWidgetPlugin.kt: (19, 1): Class 'HomeWidgetPlugin' is not abstract and does not implement abstract member public abstract fun onNewIntent(p0: Intent): Boolean defined in io.flutter.plugin.common.PluginRegistry.NewIntentListener
    e: D:\flutter\flutter\.pub-cache\hosted\pub.dartlang.org\home_widget-0.1.5\android\src\main\kotlin\es\antonborri\home_widget\HomeWidgetPlugin.kt: (193, 5): 'onNewIntent' overrides nothing
    
    opened by setcy 4
  • ListView Help

    ListView Help

    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

    opened by Nightbl927 4
  • Does not work after version 3.0.5 of flutter (home_widget 0.1.6)

    Does not work after version 3.0.5 of flutter (home_widget 0.1.6)

    If you use flutter > 3.0.5 you get this error if you build in release-mode and try a buttonclick on the widget: https://stackoverflow.com/questions/74675682/flutter-dart-error-dart-lookuplibrary-library-packagehome-widget-home-widget

    the solution with @pragma('vm:entry-point') doesnt work for me

    Plugin works with this setup:

    pubspec.yaml environment: sdk: '>=2.17.0 <3.0.0'

    with flutter version 3.0.5

    "--release flag won't let service extensions run (see the docs here)." https://stackoverflow.com/a/73613366

    "Service extensions are disabled." https://docs.flutter.dev/testing/build-modes#release

    EDIT: oh maybe it needs to be @pragma("vm:entry-point") with doublequotes instead of @pragma('vm:entry-point') it worked now with flutter 3.3.10 (and environment: sdk: '>=2.17.6 <3.0.0')

    opened by baststar 0
  • Problems to run on iOS

    Problems to run on iOS

    I'm having trouble getting it to run on iOS, the documentation isn't very clear on how I should go about setting it up, could anyone help me with that?

    Screenshot 2023-01-02 at 12 38 29 Screenshot 2023-01-02 at 12 40 16
    opened by ribeiroevandro 0
  • Trouble with just_audio, just_audio_background, or audio_service

    Trouble with just_audio, just_audio_background, or audio_service

    When adding adding libraries just_audio, just_audio_background, or audio_service, which require changing class MainActivity : FlutterActivity() to class MainActivity : com.ryanheise.audioservice.AudioServiceActivity(), the behavior is unexpected. See ticket here https://github.com/ryanheise/audio_service/issues/875#issuecomment-1369020543

    opened by adrianvintu 0
  • Loading between updates

    Loading between updates

    When i call await HomeWidget.updateWidget to change my Widget tab or info, the android widget has a fast change to "Loading..." and then the new data appears, is there any way to avoid this?

    https://user-images.githubusercontent.com/10541221/206686211-90104a32-7739-49d9-b56a-f71ca101a702.mp4

    opened by thize 0
  • Error with sdk: =2.16.1 <3.0.0"">

    Error with sdk: ">=2.16.1 <3.0.0"

    with the sdk: ">=2.16.1 <3.0.0" error in: void initState() { super.initState(); HomeWidget.setAppGroupId('YOUR_GROUP_ID'); HomeWidget.registerBackgroundCallback(backgroundCallback); // ERROR HERE }

    /* The argument type 'void Function(Uri)' can't be assigned to the parameter type 'dynamic Function(Uri?)'. */

    unfortunately I can't change my sdk, are there any solutions?

    opened by virtualars 0
Releases(v0.2.0)
Owner
Anton Borries
Anton Borries
Flutter package: Assorted layout widgets that boldly go where no native Flutter widgets have gone before.

assorted_layout_widgets I will slowly but surely add interesting widgets, classes and methods to this package. Despite the package name, they are not

Marcelo Glasberg 122 Dec 22, 2022
A Flutter plugin that makes it easier to make floating/overlay windows for Android with pure Flutter

flutter_floatwing A Flutter plugin that makes it easier to make floating/overlay windows for Android with pure Flutter. Android only Features Pure Flu

Zoe 116 Dec 21, 2022
A draggable Flutter widget that makes implementing a Sliding up and fully-stretchable much easier.

Draggable Home A draggable Flutter widget that makes implementing a Sliding up and fully-stretchable much easier! Based on the Scaffold and Sliver. Us

Devs On Flutter 106 Dec 12, 2022
Flutter-useful-widgets - Flutter Useful Widgets

useful_widgets This package makes it easy to build apps by providing a list of simple and useful widgets. import 'package:useful_widgets/useful_widget

Ricardo Crescenti 6 Jun 20, 2022
Custom widgets and utils using Flutter framework widgets and Dart language

reuse_widgets_and_utils The custom widgets and utils using Flutter framework widgets and Dart programming language. Getting Started This project is a

null 1 Oct 29, 2021
Widgets beginner - Widgets beginner with flutter

Widgets beginner - Widgets beginner with flutter

Tukhtamurodov Sardorbek 2 Feb 6, 2022
This flutter package provides an easy implementation of a Slider Button to cancel current transaction or screen

This flutter package provides an easy implementation of a Slider Button to cancel current transaction or screen

null 222 Nov 8, 2022
Flutter UI Widgets Flutter Package

Flutter UI Widgets Flutter Package This package makes different Flutter UI widgets implementation easy for you. Flutter UI Widgets The list of widgets

Hassan Ur Rahman 0 May 6, 2022
A Flutter package which provides helper widgets for selecting single or multiple account/user from the given list.

account_selector A Flutter package which provides helper widgets for selecting single or multiple account/user from a list Supported Dart Versions Dar

Harpreet Singh 49 Oct 7, 2021
A new flutter package for collection of common popular social media widgets

Social Media Widgets - package A new flutter package for collection of common popular social media widgets Currently available widgets Snapchat screen

theboringdeveloper 34 Nov 12, 2022
Multi select flutter tejpal - A package for creating multi-select widgets in a variety of ways

Multi select flutter tejpal - A package for creating multi-select widgets in a variety of ways

Tejpal Singh 3 Jul 11, 2022
A flutter package which provides most commonly used widgets with their normal and neon version

This is a flutter package which provides most commonly used widgets with their normal and neon version. There are multiple different types of widgets under this package, which can be used to create more neon theme widget

ojas 24 Oct 7, 2022
Pal-Widgets - A flutter package for better onboarding

Pal widgets A flutter package for better onboarding. A set of amazing onboarding widgets for your flutter applications. Install package add in your pu

Dominique Rwema Bagirishya 31 Oct 6, 2022
This package supports drag & drop widgets inside the GridView.builder for multiplatform

This package supports drag & drop widgets inside the GridView.builder for multiplatform. It provides all the properties which are available in Gridview. builder and easy to implement with the few lines of code.

MindInventory 68 Dec 29, 2022
Various Flutter widgets that are developed by Google but not by the core Flutter team

Flutter widgets This repository contains the source code for various Flutter widgets that are developed by Google but not by the core Flutter team. Is

Google 1.1k Jan 7, 2023
React hooks for Flutter. Hooks are a new kind of object that manages a Widget life-cycles. They are used to increase code sharing between widgets and as a complete replacement for StatefulWidget.

English | Português Flutter Hooks A Flutter implementation of React hooks: https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889 Ho

Remi Rousselet 2.6k Dec 29, 2022
Code generation for Flutter Padding widgets based on your constants

Code generation for Flutter Padding widgets based on your constants

Emanuele 14 Oct 20, 2022
Flutter widgets and themes implementing the current macOS design language.

macos_ui Flutter widgets and themes implementing the current macOS design language. NOTE: This package depends on the excellent native_context_menu pl

Reuben Turner 1.1k Jan 7, 2023
This repo is for anything that can be reusable in flutter like custom widgets 🟥, animations 🌟and more

Flutter Shortcuts This repo is for anything that can be reusable in flutter like custom widgets ?? , animations ?? and more. How to Use Just get the f

Abdelrahman Mostafa Elmarakby 91 Dec 3, 2022