gitn00b1337 / expo-widgets

Bringing widget functionality to expo!
145 stars 12 forks source link

Android Widget using Android BroadcastReceiver #4

Closed OmkoBass closed 8 months ago

OmkoBass commented 10 months ago

Hi, I'm trying to implement an android widget that will update it's data every time the screen unlocks.

I have tried many things but I can't wrap my head around this. How would I implement that? Where do I write that code?

Stackoverflow Suggestion says that we have to use some BroadcastReceiver but I don't know where that should be written.

Please, any help is appreciated!

gitn00b1337 commented 10 months ago

Hi,

There's two options.

  1. Take a look at the example folder of this project. There's an AppWidgetProvider class in widgets/android/src/SampleWidget.kt. Here you should be able to add an onReceive method like here: https://stackoverflow.com/questions/18545773/android-update-widget-from-broadcast-receiver Then update the XML in one of the correct files.
  2. Keep it in react native land and use AppState in an effect and pass data to the widget as shown in the readme & example.

I'm not an Android dev but happy to help if you make a small example project and get stuck somewhere.

OmkoBass commented 10 months ago

Hey,

First off, I want to thank you for the quick response. What you suggested could actually work, but I have a problem following your steps in the README.md file.

Do i just copy the widget directory or is there a way to initialize native code of some sorts? My plugin directory is not creating a build directory inside of it.

Am i missing something?

gitn00b1337 commented 10 months ago

The widget directory is whatever path you specify in the settings json. You should install the npm package not copy the repo. The example folder should make it clear what needs to be done

OmkoBass commented 10 months ago

I looked at the example folder and also installed the npm package, but still I couldn't figure out how to actually add the widget, nor how the plugin directory works.

I know that i can create a widgets directory and add the code, but that does not help me much. I wouldn't create an issue if I didn't help.

gitn00b1337 commented 10 months ago

If you want to understand the repository then take a look at expo modules and expo plugins. The plugin folder just provides the package functionality to hook up native code with expo. You just have to let the library know where your folders are and it does the rest by providing the json config. Not sure if I'm misunderstanding you?

OmkoBass commented 10 months ago

I think I understand you now.

Steps I made:

But it's not compiling, I'm getting lots of deprecation warnings because for some reason i needed JDK 11.

After that I had a problem saying Could not reserve enough space for 2097152KB object heap which I resolved by commenting out org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m inside the gradle.properties.

After that I'm getting a critical error Unresolved reference: R. I've resolved the Unresolved reference: R problem by including import android.R in the widgets directory.

Now I'm getting an error saying: Unresolved reference: sample_widget, So this probably means something is not correctly setup and that's why the files are not recognized.

This is my widgets directory.

└───widgets
    └───android
        └───src
            ├───main
            │   └───java
            │       └───package_name
            │       └──── SampleWidget.kt
            └───res
                ├───drawable-nodpi
                ├───drawable-v21
                ├───layout
                ├───values
                ├─────sample_widget.xml
                ├───values-night-v31
                ├───values-v21
                ├───values-v31
                └───xml

The SampleWidget.kt contains:

package expo.modules.widgets.example;

import android.R
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.widget.RemoteViews
import android.content.SharedPreferences

/**
 * Implementation of App Widget functionality.
 */
class SampleWidget : AppWidgetProvider() {
    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray
    ) {
        // There may be multiple widgets active, so update all of them
        for (appWidgetId in appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId)
        }
    }

    override fun onEnabled(context: Context) {
        // Enter relevant functionality for when the first widget is created
    }

    override fun onDisabled(context: Context) {
        // Enter relevant functionality for when the last widget is disabled
    }
}

internal fun updateAppWidget(
    context: Context,
    appWidgetManager: AppWidgetManager,
    appWidgetId: Int
) {
    //val widgetText = context.getString(R.string.appwidget_text)
    val widgetText = context.getSharedPreferences(context.packageName + ".widgetdata", Context.MODE_PRIVATE).getString("widgetdata", "{}")

    val views = RemoteViews(context.packageName, R.layout.sample_widget)
    views.setTextViewText(R.id.appwidget_text, widgetText)

    // Instruct the widget manager to update the widget
    appWidgetManager.updateAppWidget(appWidgetId, views)
}

The sample_widget.xml contains:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/Widget.EASWidgetExample.AppWidget.Container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:theme="@style/AppTheme.AppWidgetContainer">

    <TextView
        android:id="@+id/appwidget_text"
        style="@style/Widget.EASWidgetExample.AppWidget.InnerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_margin="8dp"
        android:contentDescription="@string/appwidget_text"
        android:text="@string/appwidget_text"
        android:textSize="24sp"
        android:textStyle="bold|italic" />
</RelativeLayout>

I don't know how to fix this, so please, help would be appreciated.

gitn00b1337 commented 10 months ago

Do you have android studio installed? I'd recommend creating a widget project there (simple template one) and then copying the folders across. It sounds like there's a lot of dependency issues for you, likely due to environment mismatch.

OmkoBass commented 10 months ago

Yes I have android studio. How do I create the "widget project"? I can choose New Project -> There are Empty Activity (Jetpack Compose), No Activity and other Activities. I've no idea how to create the "template widget project".

gitn00b1337 commented 10 months ago

https://developer.android.com/develop/ui/views/appwidgets

OmkoBass commented 10 months ago

I'll check it out and try to make it work, thank you!

It would be extremely helpful if you could create a bare expo router project and add the widgets so that others and I that have the same problem can clone it and have working widgets. Also that potentially means less open issues like this one.

gitn00b1337 commented 10 months ago

There is in the example folder of this repository. What would you like expanding on it?