sAleksovski / react-native-android-widget

Build Android Widgets with React Native
https://sAleksovski.github.io/react-native-android-widget/
MIT License
578 stars 22 forks source link

Widget loading problem on android 6 (API 23) #85

Closed outaTiME closed 4 months ago

outaTiME commented 4 months ago

Hello there, I am doing some tests with my widget on different versions of android and on version 6 (API 23) the widget does not load and the following error appears:

CleanShot 2024-05-09 at 11 40 21

I put different traces and the task handler along with the rendering of the widget is running correctly.

Notice, I'm using Expo 50 and this only happens with this specific version of Android, I don't know if anyone else experienced this kind of problem.

Here some code along with the plugin definition in the app.config:

// app.config.js

[
  'react-native-android-widget',
  {
    fonts: ['./assets/fonts/FiraGO-Regular-Minimal.otf'],
    widgets: [
      {
        name: 'Rate',
        // https://developer.android.com/guide/practices/ui_guidelines/widget_design?hl=es-419
        // 70 * n − 30 (2x2)
        minWidth: '110dp',
        minHeight: '110dp',
        label: 'Cotizaciones',
        description:
          'Mantenete al tanto de las cotizaciones durante el transcurso del día.',
        previewImage: './assets/widgets/android-2x2.png',
        resizeMode: 'none',
        widgetFeatures: 'reconfigurable|configuration_optional',
        // https://saleksovski.github.io/react-native-android-widget/docs/public-api/interfaces/Widget#updateperiodmillis
        updatePeriodMillis: 30 * 60 * 1000,
      },
    ],
  },
]

// widget

import React from 'react';
import { FlexWidget, TextWidget } from 'react-native-android-widget';

export default function RateWidget(props) {
  const size = props.size || 130;
  const padding = 14;
  const borderRadius = 20;
  return (
    <FlexWidget
      style={{
        height: 'match_parent',
        width: 'match_parent',
        justifyContent: 'center',
        alignItems: 'center',
      }}
    >
      <FlexWidget
        style={{
          height: size,
          width: size,
          backgroundColor: '#000',
          padding,
          borderRadius,
        }}
      >
        <TextWidget
          text="Blue"
          style={{
            fontSize: 18,
            fontFamily: 'FiraGO-Regular-Minimal',
            color: '#FFF',
          }}
          maxLines={1}
        />
        <FlexWidget style={{ flex: 1, justifyContent: 'flex-end' }}>
          <TextWidget
            text="0.00% ="
            style={{
              fontSize: 12,
              fontFamily: 'FiraGO-Regular-Minimal',
              color: 'rgba(10,132,255,1)',
            }}
            maxLines={1}
          />
          <TextWidget
            text="1,025.00"
            style={{
              fontSize: 24,
              fontFamily: 'FiraGO-Regular-Minimal',
              color: '#FFF',
            }}
            maxLines={1}
          />
          <TextWidget
            text="25/04 15:45"
            style={{
              fontSize: 10,
              fontFamily: 'FiraGO-Regular-Minimal',
              color: 'rgba(142,142,147,1)',
              marginTop: 5,
            }}
            maxLines={1}
          />
        </FlexWidget>
      </FlexWidget>
    </FlexWidget>
  );
}
sAleksovski commented 4 months ago

Does pressing the X button call setResult('ok')?

Can you share the js and adb logs?

outaTiME commented 4 months ago

Indeed, the x button press makes a call to props.setResult('ok'), (as I mentioned before) in the other android versions it works as expected. It seems to be something exclusive of this version.

The JS of the configuration screen has quite a lot of code (and I don't have it uploaded yet in my repository) but its general structure is the following:

<GestureHandlerRootView style={{ flex: 1 }}>
  <SafeAreaProvider>
    <ThemeProvider theme={theme}>
      <HeaderButtonsProvider stackType="native">
        <ScrollView>
          <ContentView contentContainerStyle={{ flex: 1 }}>
            <View
              style={{
                paddingVertical: Settings.CARD_PADDING,
                marginHorizontal: Settings.CARD_PADDING,
                flexDirection: 'row',
                marginBottom: -Settings.CARD_PADDING,
                justifyContent: 'flex-end',
              }}
            >
              <MaterialHeaderButtons>
                <Item
                  title="Cerrar"
                  iconName="close"
                  onPress={() => {
                    props.setResult('ok');
                  }}
                  buttonStyle={{
                    marginHorizontal: Settings.PADDING,
                  }}
                />
              </MaterialHeaderButtons>
            </View>
            <CardView title="Cotización" plain>
              {rateTypes.map((type, index) => (
                <CardItemView
                  key={type}
                  title={AmbitoDolar.getRateTitle(type)}
                  useSwitch={false}
                  chevron={false}
                  check={
                    config.rate === type || (!config.rate && index === 0)
                  }
                  onAction={() => {
                    saveSetting('rate', type);
                  }}
                />
              ))}
            </CardView>
            <CardView title="Mostrar" plain>
              {['buy', 'average', 'sell'].map((type, index) => (
                <CardItemView
                  key={type}
                  title={I18n.t(type)}
                  useSwitch={false}
                  chevron={false}
                  check={
                    config.value === type ||
                    (!config.value && index === 2)
                  }
                  onAction={() => {
                    saveSetting('value', type);
                  }}
                />
              ))}
            </CardView>
          </ContentView>
        </ScrollView>
      </HeaderButtonsProvider>
    </ThemeProvider>
  </SafeAreaProvider>
</GestureHandlerRootView>

in a while I will see if I can see some logs inside the ADB

sAleksovski commented 4 months ago

I meant js log if there are some errors there.

My guess is that some of the APIs used in the java code are not available in Android 6, and there should be some error in the adb log.

outaTiME commented 4 months ago

I meant js log if there are some errors there.

My guess is that some of the APIs used in the java code are not available in Android 6, and there should be some error in the adb log.

I understand, I was looking at the execution logcat when placing a widget on the screen and there is an exception coming from android.widget.FrameLayout, I leave the full log here (collapsed).

Click to see full log ``` START u0 {act=android.appwidget.action.APPWIDGET_CONFIGURE cmp=im.outa.AmbitoDolar/.WidgetConfigurationActivity (has extras)} from uid 1000 on display 0 Running "RNWidgetConfigurationScreen eglMakeCurrent: 0x7238bfdb20: ver 3 0 (tinfo 0x7239225c60) [GESTURE HANDLER] Initialize gesture handler for root view com.facebook.react.ReactRootView{e2d0aca V.E...... ......ID 0,0-1080,2082 #1f} Displayed im.outa.AmbitoDolar/.WidgetConfigurationActivity: +81ms eglMakeCurrent: 0x73ce6de5a0: ver 3 0 (tinfo 0x73ce6c2e80) getSlotFromBufferLocked: unknown buffer: 0x73bfdd8fa0 '>>> taskHandler (renderWidget)', '2024-05-09T14:23:51-03:00', { size: 137, type: 'oficial', change: 0.05, value: 924.06, timestamp: '2024-05-09T12:35:24-03:00' } '>>> RateWidget', false, 'dark', 137, 'oficial', 0.05, 924.06, '2024-05-09T12:35:24-03:00' Worker result SUCCESS for Work [ id=22e41259-8063-4c27-acbd-653eb63d6cb8, tags={ com.reactnativeandroidwidget.RNWidgetBackgroundTaskWorker } ] Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 eglMakeCurrent: 0x73ce6de5a0: ver 3 0 (tinfo 0x73ce6c2e80) eglMakeCurrent: 0x7238bfdb20: ver 3 0 (tinfo 0x7239225c60) getSlotFromBufferLocked: unknown buffer: 0x73caa67980 endAllStagingAnimators on 0x72366dc400 (ReactViewGroup) with handle 0x73caa7cfc0 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Points are too far apart 4.030360828967057 Points are too far apart 4.030360538880159 Memory warning (pressure level: TRIM_MEMORY_UI_HIDDEN) received by JS VM, ignoring because it's non-severe Tried to remove non-existent frame callback Incorrectly called buildLayer on View: ShortcutAndWidgetContainer, destroying layer... Incorrectly called buildLayer on View: ShortcutAndWidgetContainer, destroying layer... updateAppWidget couldn't find any view, using error view android.widget.RemoteViews$ActionException: view: android.widget.FrameLayout can't use method with RemoteViews: setMinimumHeight(int) at android.widget.RemoteViews.getMethod(RemoteViews.java:778) at android.widget.RemoteViews.-wrap2(RemoteViews.java) at android.widget.RemoteViews$ReflectionAction.apply(RemoteViews.java:1296) at android.widget.RemoteViews.performApply(RemoteViews.java:2804) at android.widget.RemoteViews.apply(RemoteViews.java:2764) at android.widget.RemoteViews$ViewGroupAction.apply(RemoteViews.java:1373) at android.widget.RemoteViews.performApply(RemoteViews.java:2804) at android.widget.RemoteViews.apply(RemoteViews.java:2764) at android.appwidget.AppWidgetHostView.updateAppWidget(AppWidgetHostView.java:393) at com.android.launcher3.LauncherAppWidgetHostView.updateAppWidget(LauncherAppWidgetHostView.java:69) at android.appwidget.AppWidgetHost.createView(AppWidgetHost.java:349) at com.android.launcher3.LauncherAppWidgetHost.createView(LauncherAppWidgetHost.java:118) at com.android.launcher3.Launcher.completeTwoStageWidgetDrop(Launcher.java:930) at com.android.launcher3.Launcher$10.run(Launcher.java:818) at com.android.launcher3.Workspace$4.onAnimationEnd(Workspace.java:780) at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1239) at android.animation.ValueAnimator$AnimationHandler.doAnimationFrame(ValueAnimator.java:766) at android.animation.ValueAnimator$AnimationHandler$1.run(ValueAnimator.java:801) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858) at android.view.Choreographer.doCallbacks(Choreographer.java:670) at android.view.Choreographer.doFrame(Choreographer.java:603) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) dataChanged but no participant pkg='com.android.launcher3' uid=10009 hw_composer sent 1037 syncs in 60s hw_composer sent 9 syncs in 60s ```
sAleksovski commented 4 months ago

Looks like a part of the log is missing, since there is no reference to code from this library in the log.

From the log it seems to fail on setMinimumHeight, which is called for clickable views (which is strange because you don't have clickAction in your widget).

setMinimumHeight is called to set up the "button" in the widget which can be clicked. This was implemented in another way before, but in some cases the "button" was not on the correct place in the widget, and setMinimumHeight had to be used.

Looks like setMinimumHeight became "RemotableViewMethod" in Android 7

Android 7 https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-7.0.0_r34/core/java/android/view/View.java#19996

Android 6 https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-6.0.1_r81/core/java/android/view/View.java#19056

Did you remove clickAction from the example above? If not, can you share more of the log?

outaTiME commented 4 months ago

I'm looking at the log from the Android Studio, and it represents the moment I drag the widget from the palette, drop it and close the configuration window.

I don't see any reference to your library, should I open the application? The compilation I'm running is preview (practically productive), would it be useful to try another type of compilation on the dev client?

On the other hand, it is correct what you say, the widget code that I attached was a simple version of the original one uses the clickAction:

import React from 'react';
import { FlexWidget, TextWidget } from 'react-native-android-widget';

export default function RateWidget(props) {
  const size = props.size || 130;
  const padding = 14;
  const borderRadius = 20;
  return (
    <FlexWidget
      style={{
        height: 'match_parent',
        width: 'match_parent',
        justifyContent: 'center',
        alignItems: 'center',
      }}
    >
      <FlexWidget
        style={{
          height: size,
          width: size,
          backgroundColor: '#000',
          padding,
          borderRadius,
        }}
        clickAction="OPEN_URI"
        clickActionData={{
          uri: 'ambito-dolar://rates',
        }}
      >
        <TextWidget
          text="Blue"
          style={{
            fontSize: 18,
            fontFamily: 'FiraGO-Regular-Minimal',
            color: '#FFF',
          }}
          maxLines={1}
        />
        <FlexWidget style={{ flex: 1, justifyContent: 'flex-end' }}>
          <TextWidget
            text="0.00% ="
            style={{
              fontSize: 12,
              fontFamily: 'FiraGO-Regular-Minimal',
              color: 'rgba(10,132,255,1)',
            }}
            maxLines={1}
          />
          <TextWidget
            text="1,025.00"
            style={{
              fontSize: 24,
              fontFamily: 'FiraGO-Regular-Minimal',
              color: '#FFF',
            }}
            maxLines={1}
          />
          <TextWidget
            text="25/04 15:45"
            style={{
              fontSize: 10,
              fontFamily: 'FiraGO-Regular-Minimal',
              color: 'rgba(142,142,147,1)',
              marginTop: 5,
            }}
            maxLines={1}
          />
        </FlexWidget>
      </FlexWidget>
    </FlexWidget>
  );
}
sAleksovski commented 4 months ago

I think I will have to disable clickAction on Android 6, since that method is not available.

I could try to use a different approach only for Android 6, but that had other issues like clickable area on wrong place in the widget.

sAleksovski commented 4 months ago

I released 0.13.2 that disables clickAction on Android 6, can you try again?

outaTiME commented 4 months ago

I released 0.13.2 that disables clickAction on Android 6, can you try again?

Thanks @sAleksovski, the new version worked perfectly logically without clickAction but it does not bother and especially considering that soon this version of android is no longer supported.