ABausG / home_widget

Flutter Package for Easier Creation of Home Screen Widgets
752 stars 203 forks source link

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

Closed huytower closed 3 years ago

huytower commented 3 years ago

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))
    }
}
ABausG commented 3 years ago

You need to call: HomeWidget.updateWidget with

iOSName: 'nct_home_widget'

As described in the README the Name for the iOS Widget needs to be equal to that specified in kind in the Widget implementation on iOS

huytower commented 3 years ago

I already changed as you details, but it does not work (already uninstalled old app).

What I have missed?

Future<void> updateWidget() async {
    print('updateWidget() ');

    try {
      return HomeWidget.updateWidget(
          name: 'HomeWidgetExampleProvider',
          androidName: 'HomeWidgetExampleProvider',
          iOSName: 'nct_home_widget'
      );
          // iOSName: 'HomeWidgetExample');
    } on PlatformException catch (exception) {
      debugPrint('Error Updating Widget. $exception');
    }
  }
leonardocustodio commented 3 years ago

This part in the swift file: private let widgetGroupId = "nct_home_widget"

Should be your appgroup and not the string that you provide in the updateWidget. So it must starts with: group.something People usally make something like: group.com.inovatso.picPics.Widget (group + your reverse bundle id + something)

Also did you add the app group to the main target as well as to the plugin?

huytower commented 3 years ago

Hello,

I tried as your recommend, Rebuilt but it did not work.

Please see these images to correct me.

Thanks,

Code Screen Shot 2020-12-18 at 16 13 51 Screen Shot 2020-12-18 at 16 14 18

*.entitlements Screen Shot 2020-12-18 at 16 56 42

App Group Screen Shot 2020-12-18 at 16 14 43 Screen Shot 2020-12-18 at 16 12 16

ABausG commented 3 years ago

Could you try to solve the issues regarding the provisioning profile pointed out by Xcode?

sharathGowda12 commented 3 years ago

Facing the same issue.

Double checked all the setup details and done everything as per docs.

here is the code sample


1. Future<void> _saveHomeWidget(title01, mesaage01) async {
2.     try {
3.       print('Save value Started');
4.       return Future.wait([
5.         HomeWidget.saveWidgetData<String>('title', title01),
6.         HomeWidget.saveWidgetData<String>('message', mesaage01),
7.       ]).then((value) => {
8.         print('SAVED Value'), 
9.         print(value)
10.         });
11.     } on PlatformException catch (exception) {
12.       debugPrint('Error Sending Data. $exception');
13.     }
14.   }
15. 
16.   Future<void> _updateWidget() async {
17.     try {
18.       print('update value Started');
19.       return HomeWidget.updateWidget(
20.               name: 'HomeWidgetForSys',
21.               androidName: 'HomeWidgetForSysAndroid',
22.               iOSName: 'HomeWidgetForSys')
23.           .catchError((error) {
24.         print('error');
25.       }).then((value) => {
26.         print('UPDATED Value'),
27.          print(value)
28.          });
29.     } on PlatformException catch (exception) {
30.       debugPrint('Error Updating Widget. $exception');
31.     }
32.   }
33. 
34.   Future<void> _retrieveData() async {
35.     try {
36.       print('retrieve value Strted');
37.       return HomeWidget.getWidgetData<String>('message', defaultValue: 'data')
38.           .then((value01) => {
39.             print('RETRIEVED Value'), 
40.             print(value01)
41.             });
42.     } on PlatformException catch (exception) {
43.       debugPrint('Error Retrieving Widget. $exception');
44.     }
45.   }
46. 
47.   Future<void> _sendAndUpdate(title01, mesaage01) async {
48.     await _saveHomeWidget(title01, mesaage01);
49.     await _retrieveData();
50.     await _updateWidget();
51.   }

Here the snapshot of print statement Screenshot 2021-04-07 at 3 48 05 PM

Note that values are saving and even the retrieving(getWidgetData<>) is also working, but the widget is not updating.

Few more details Flutter version - 2.0.4 - stable XCode - 12.4 home_widget - latest

Any other details, if needed will be provided.

ABausG commented 3 years ago

Could you also provide the code of your iOS Widget? Also a Screenshot of the signing portion in Xcode to make sure the app group is setup correctly?

sharathGowda12 commented 3 years ago

Hi,

find the attached

Screenshot 2021-04-10 at 9 45 24 AM

iOS Widget code // used home-widget example code

import WidgetKit
 import SwiftUI

  private let widgetGroupId = "group.homewidget.sernal"

 struct Provider: TimelineProvider {
     func placeholder(in context: Context) -> SimpleEntry {
         SimpleEntry(date: Date(), title: "My Goal",
                     message: "Add your goal from Sernal main Screen")
     }

     func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
         let data = UserDefaults.init(suiteName:widgetGroupId)
         print("getSnapshot")
         let entry = SimpleEntry(date: Date(), title: "My Goal",
                     message: data?.string(forKey: "message")
                     ?? "Add your goal from Sernal ")
         completion(entry)
     }

     func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        //To check here to update widget data
         getSnapshot(in: context) { (entry) in
             let timeline = Timeline(entries: [entry], policy: .atEnd)
             completion(timeline)
         }

     }
 }

 struct SimpleEntry: TimelineEntry {
     let date: Date
     let title: String
     let message: String
 }

 struct HomeWidgetForSernalEntryView : 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).font(.body)
             Text(entry.message).bold().font(.title)
             .widgetURL(URL(string: "HomeWidgetForSernal://openmainscreen"))
         })
     }
 }

 @main
 struct HomeWidgetForSernal: Widget {
     let kind: String = "HomeWidgetForSernal"

     var body: some WidgetConfiguration {
         StaticConfiguration(
             kind: kind,
             provider: Provider()) { entry in
             HomeWidgetForSernalEntryView(entry: entry)
             .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.gray)
         }
         .configurationDisplayName("My Goal")
         .description("Your added goals are displayed like this.").supportedFamilies([.systemMedium, .systemLarge])
     }
 }

 struct HomeWidgetForSernal_Previews: PreviewProvider {
     static var previews: some View {
         HomeWidgetForSernalEntryView(entry: SimpleEntry(date: Date(), title: "My Goal",
                     message: "My added Goals."))
            .previewContext(WidgetPreviewContext(family: .systemMedium))
     }
 }
ABausG commented 3 years ago

I think you are missing the App Group Capability in your App.

Go to: Signing & Capabilities > +Capabilities > App Group

sharathGowda12 commented 3 years ago

App group is in both runner & widget, please find the attached. Edit:- YES, it was missing before, later on I added & checked with rebuild, Clean, still the same problem.

Screenshot 2021-04-12 at 9 16 52 AM

Screenshot 2021-04-12 at 9 18 12 AM

ABausG commented 3 years ago

The Widget seems to only declare the App Group for Profile Builds, not sure if that might be it? Also just to make sure: You did add the App Group on the Apple Developer Page?

sharathGowda12 commented 3 years ago

Thanks for your time & patience.

Now it is working.

ABausG commented 3 years ago

@huytower Does this help you as well?

ihadabs commented 3 years ago

For those how might encounter this problem as @ABausG said, make sure to add the app groups to debug, profile, and release.

Make sure you select all: image

See here its not added to the debug: image

When add to all it will look like this: image

@ABausG Thanks man!

huytower commented 3 years ago

let me check in next week.