home_widget icon indicating copy to clipboard operation
home_widget copied to clipboard

WidgetClick does not trigger

Open petrnymsa opened this issue 2 years ago • 30 comments

I am trying to integrate package to our existing application but I have no luck with listening on WidgetClick.

I've followed Readme guide and I am sure that I am something missing but don't know what.

I've added inten-filter under main activity

 <intent-filter>
      <action android:name="es.antonborri.home_widget.action.LAUNCH" />
   </intent-filter>

WidgetProvider is configured like so

  <receiver
          android:name=".widget.TimetableWidgetProvider"
          android:label="@string/widget_app_name"
          android:exported="true">
      <intent-filter>
          <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
      </intent-filter>

      <meta-data
              android:name="android.appwidget.provider"
              android:resource="@xml/widget_info" />
  </receiver>

Widget_info,XML looks like this

<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/widget_layout"
    android:minHeight="180dp"
    android:minResizeHeight="110dp"
    android:minWidth="320dp"
    android:minResizeWidth="110dp"
    android:resizeMode="vertical|horizontal"
    android:updatePeriodMillis="900000"
    android:widgetCategory="home_screen">

</appwidget-provider>

And widget layout is

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget_base_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="8dip"
    android:background="@drawable/widget_background"
    android:orientation="vertical"
    android:padding="2dp">

    <include layout="@layout/header_layout" />

    <GridView
        android:id="@+id/grid_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="4" />

    <TextView
        android:id="@+id/empty_grid_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/timetable_empty"
        android:layout_gravity="center"
        android:gravity="center"
        android:visibility="gone" />
</LinearLayout>

In TimetableWidgetProvider.kt I have practically this

   override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
        appWidgetIds.forEach { widgetId ->
            val views = RemoteViews(context.packageName, R.layout.widget_layout).apply {
                // Open App on Widget Click
                val pendingIntent = HomeWidgetLaunchIntent.getActivity(
                        context,
                        MainActivity::class.java)
                setOnClickPendingIntent(R.id.widget_base_layout, pendingIntent)
            }

            appWidgetManager.updateAppWidget(widgetId, views)

        }


        val intent = Intent(context, TimetableDataService::class.java)
        intent.action = TimetableDataService.WIDGET_UPDATE_ACTION
        intent.putExtra(TimetableDataService.WIDGET_IDS, appWidgetIds)
        JobIntentService.enqueueWork(context, TimetableDataService::class.java, 1, intent)
    }

I will provider more info if needed. Thanks.

petrnymsa avatar Feb 16 '22 17:02 petrnymsa

What exactly do you want to achieve with the click? To me it looks like the code above should open the app when clicking on the widget. Does it do that?

If you want to check in the app if the app was launched from the widget you should check:

https://github.com/ABausG/home_widget#clicking

If you want to know which specific view was clicked/send data you need to add a Uri to the Intent as seen on the example section here:

https://github.com/ABausG/home_widget#android

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

ABausG avatar Feb 17 '22 06:02 ABausG

@ABausG I want to just know that App was opened via Widget.

App itself is opening when widget is clicked, but listener does not work.

petrnymsa avatar Feb 17 '22 08:02 petrnymsa

@ABausG Any clues how to fix this? Still no progress

petrnymsa avatar Feb 21 '22 10:02 petrnymsa

Could you also provide the dart code you are using to listen to the callbacks?

Make sure that HomeWidget.initiallyLaunchedFromHomeWidget() only works for the initial launch of the app. If the app is already opened in the background you need to also listen to HomeWidget.widgetClicked

ABausG avatar Feb 21 '22 13:02 ABausG

Basically like this

_widgetClickSub = HomeWidget.widgetClicked.listen((uri) {
      print(uri);
      
    });
Listener is hooked up in state object which is alive upon whole life of application so it should be ok. 

petrnymsa avatar Feb 21 '22 15:02 petrnymsa

Could you also try to additional check the result of initiallyLaunchedFromWidget() ?

ABausG avatar Feb 21 '22 15:02 ABausG

initiallyLaunchedFromWidget() returns null.

I've compared everything I could with example project and nothing seems off, but still, listener does not trigger. .. Right now, I've cloned plugin and tried to add some debug logs into Android's plugin itself.. Hopefully I will find something that could help.

petrnymsa avatar Feb 21 '22 15:02 petrnymsa

Ok little progress here:

I've added some logs into HomeWidgetPlugin.kt , mainly to onListen and onReceive where intents are filtered...


  private fun createReceiver(events: EventChannel.EventSink?): BroadcastReceiver {
        return object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                Log.d("HomeWidget", "onReceive $intent");
                Log.d("HomeWidget", intent?.action ?: "INTENT NULL");
                if (intent?.action.equals(HomeWidgetLaunchIntent.HOME_WIDGET_LAUNCH_ACTION)) {
                    events?.success(intent?.data?.toString() ?: true)
                }
            }

        }
    }

Upon widget click I am getting

D/HomeWidget(10958): onNewIntent Intent { flg=0x10400000 cmp=cz.bakalari.mobile.dev/com.quichesoft.bakalari.MainActivity bnds=[82,534][999,1337] }
D/HomeWidget(10958): onReceive Intent { flg=0x10400000 cmp=cz.bakalari.mobile.dev/com.quichesoft.bakalari.MainActivity bnds=[82,534][999,1337] }
D/HomeWidget(10958): INTENT NULL

petrnymsa avatar Feb 21 '22 15:02 petrnymsa

same here. widgetclick does not trigger

desmeit avatar Apr 01 '22 15:04 desmeit

@petrnymsa Have you figured this out? Initially widgetClick was working for me, but when I added multiple widgets it stopped working. If you've solved this, any advice would be great.

Jethro87 avatar Apr 14 '22 17:04 Jethro87

+1

mtrfnvwork avatar Apr 17 '22 19:04 mtrfnvwork

@ABausG Hoping you can dig into widgetClick not working. In my case, it stopped triggering around when I added multiple widgets using a widget bundle:

@main
struct WidgetsExample: WidgetBundle {
    @WidgetBundleBuilder
    var body: some Widget {
        Widget1()
        Widget2()
        Widget3()
    }
}

I can't, unfortunately, use this package if I can't listen for clicks. Any insight you can provide would be super helpful. Thanks.

Jethro87 avatar Apr 18 '22 16:04 Jethro87

@ABausG Hoping you can dig into widgetClick not working. In my case, it stopped triggering around when I added multiple widgets using a widget bundle:

@main
struct WidgetsExample: WidgetBundle {
    @WidgetBundleBuilder
    var body: some Widget {
        Widget1()
        Widget2()
        Widget3()
    }
}

I can't, unfortunately, use this package if I can't listen for clicks. Any insight you can provide would be super helpful. Thanks.

I've solved the problem by using Link widget:

Link(destination: URL(string: "myWidget://someAction?homeWidget")!){
    // Some widget
}

Note that you must add "homeWidget" parameter to handle the click in Dart code.

Also Link widget allow handle tap gesture only if your widget has medium or large size. To handle tap gesture in small widgets you have to use .widgetURL method. But note that this method allows handle only one gesture in the widget. If you have multiple .widgetURL methods in one widget, you will be able to handle only url specified in the last .widgetURL method. Hope it will be helpful

mtrfnvwork avatar Apr 18 '22 16:04 mtrfnvwork

@mtrfnvwork Thanks for your comment.

I did some experimenting and found something interesting. When I change my widget size to .systemMedium and use a Link instead of .widgetURL, the method widgetClick works fine. However, when I change the widget back to .systemSmall and use .widgetURL, nothing triggers.

For reference, here's my view when using .systemSmall size. Can you see anything wrong with the way I'm setting .widgetURL? Thanks in advance.

struct WidgetEntryView : View {
    var entry: WidgetEntryViewProvider.Entry
    let data = UserDefaults.init(suiteName:widgetGroupId)
    
    var body: some View {
        VStack.init(alignment: .leading, spacing: nil, content: {
            Text(entry.njTitle)
                .fontWeight(.bold)
                .multilineTextAlignment(.leading)
                .font(.title3)
                .foregroundColor(Color.white)
            Spacer()
            HStack {
                Spacer()
                Image(systemName: "plus")
                    .font(.system(size: 22.0, weight: .bold))
                    .foregroundColor(Color.white)

            }
        }
        )
        .padding(.all)
        .background(Color.clearfulBlue400)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .widgetURL(URL(string: "\(widgetUrlBase)://message?message=\(entry.message)&widget=\(widgetID)&homeWidget"))
        }
}

Jethro87 avatar Apr 18 '22 18:04 Jethro87

@Jethro87 Your code works fine for me. Check .background(Color.clearfulBlue400). In XCode I get error Type 'Color' has no member 'clearfulBlue400'

mtrfnvwork avatar Apr 18 '22 18:04 mtrfnvwork

@mtrfnvwork Thanks. I added a custom color that shows fine in the widget, so I don't think that's the problem.

I guess I'll keep digging. No idea why widgetClick is not working for me when using .widgetURL. I'll post if I manage to solve this.

Jethro87 avatar Apr 18 '22 18:04 Jethro87

@petrnymsa Have you figured this out? Initially widgetClick was working for me, but when I added multiple widgets it stopped working. If you've solved this, any advice would be great.

@Jethro87 Sorry for late response.

Make sure that your AndroidManifest contains

 <intent-filter>
   <action android:name="es.antonborri.home_widget.action.LAUNCH" />
 </intent-filter>

and add pending intent on some click

 val pendingIntent = HomeWidgetLaunchIntent.getActivity(context, MainActivity::class.java)
remoteView.setOnClickPendingIntent(R.id.widget_base_layout, pendingIntent)

We dont use in the end widgets on iOS so here I can't help

petrnymsa avatar Apr 19 '22 14:04 petrnymsa

Guys, can someone tell me about the url sceme with .widgetURL? Could it be anything like myWidget:// or have to use actual app scheme and define it somewhere? The readme doesn't mention anything about this. For me the app opens but listener isn't triggered so I guess urlScheme is not the issue but just in case.

qasim90 avatar May 12 '22 09:05 qasim90

Guys, can someone tell me about the url sceme with .widgetURL? Could it be anything like myWidget:// or have to use actual app scheme and define it somewhere? The readme doesn't mention anything about this. For me the app opens but listener isn't triggered so I guess urlScheme is not the issue but just in case.

Hey, sorry for only getting back to this now.

In order for iOS to recognise, that the app is opened from a widget you need to add the query parameter: homeWidget to the url as described in the readme (I agree that that is a bit hidden. So from the example:

Text(entry.message)
    .font(.body)
    .widgetURL(URL(string: "homeWidgetExample://message?message=\(entry.message)&homeWidget"))

I hope this clears things up?

ABausG avatar Jun 05 '22 20:06 ABausG

In my case -

I'm able to listen to the click when the app is open in the background. but when I terminated the app the widget click opens the app but doesn't trigger the listener.

I've double-checked the implementation and it's according to the readme.

Help me Please!

Akash9151 avatar Jun 28 '22 13:06 Akash9151

What is the result of `HomeWidget.initiallyLaunchedFromHomeWidget()' unfortunately it is not possible to check in the stream right away

ABausG avatar Jun 28 '22 14:06 ABausG

HomeWidget.initiallyLaunchedFromHomeWidget() doesn't get triggered then, How I can share the result of this? Am I missing something?

Also, I've noticed one thing when I launch the app through Android studio on the first run it triggers HomeWidget.initiallyLaunchedFromHomeWidget().

Akash9151 avatar Jul 05 '22 08:07 Akash9151

  • Are you experiencing this only on Android or also on iOS ?
  • Is this in your own app or the example app?

In general HomeWidget.initiallyLaunchedFromHomeWidget() returns a future that should be completed with an uri if the app was launched from the widget

ABausG avatar Jul 05 '22 08:07 ABausG

@Akash9151 The listener only works when app is in background so it'll not trigger if the app was terminated. Instead you should check HomeWidget.initiallyLaunchedFromHomeWidget() in your main.dart. If it returns true, it means the widget was clicked and you can act accordingly, like invoking the listener manually for example. Hope this helps.

qasim90 avatar Jul 06 '22 05:07 qasim90

@qasim90 , Thanks the solution works for me.

Akash9151 avatar Jul 22 '22 12:07 Akash9151