From fe6781745fc26f80fde3e8c7241a1c24feb7131d Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sat, 31 Oct 2026 13:37:10 +0100 Subject: [PATCH] fix: open the app from a widget tap without asking which build to use --- .../react-native-android-widget+0.22.1.patch | 14 +++++ .../__tests__/widget-open-explicit.test.ts | 54 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/widgets/__tests__/widget-open-explicit.test.ts diff --git a/patches/react-native-android-widget+0.22.1.patch b/patches/react-native-android-widget+0.22.1.patch index 592b58c8..d6a3c93e 100644 --- a/patches/react-native-android-widget+0.22.1.patch +++ b/patches/react-native-android-widget+0.22.1.patch @@ -24,6 +24,20 @@ index ed1af56..12c3630 100644 intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE +diff --git a/node_modules/react-native-android-widget/android/src/main/java/com/reactnativeandroidwidget/RNWidgetProvider.java b/node_modules/react-native-android-widget/android/src/main/java/com/reactnativeandroidwidget/RNWidgetProvider.java +index c138d81..bcd490d 100644 +--- a/node_modules/react-native-android-widget/android/src/main/java/com/reactnativeandroidwidget/RNWidgetProvider.java ++++ b/node_modules/react-native-android-widget/android/src/main/java/com/reactnativeandroidwidget/RNWidgetProvider.java +@@ -133,6 +133,9 @@ public class RNWidgetProvider extends AppWidgetProvider { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri)); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ++ // This app's own activity, never a chooser: another build of the app ++ // (another flavor) handles the same scheme and would be offered too. ++ intent.setPackage(context.getPackageName()); + context.startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); diff --git a/node_modules/react-native-android-widget/android/src/main/java/com/reactnativeandroidwidget/RNWidgetUtil.java b/node_modules/react-native-android-widget/android/src/main/java/com/reactnativeandroidwidget/RNWidgetUtil.java index 2a34305..711503b 100644 --- a/node_modules/react-native-android-widget/android/src/main/java/com/reactnativeandroidwidget/RNWidgetUtil.java diff --git a/src/widgets/__tests__/widget-open-explicit.test.ts b/src/widgets/__tests__/widget-open-explicit.test.ts new file mode 100644 index 00000000..3c99c863 --- /dev/null +++ b/src/widgets/__tests__/widget-open-explicit.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from 'vitest'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { open, links } from '../clicks'; + +const root = path.resolve(__dirname, '../../..'); +const patchFile = path.join(root, 'patches/react-native-android-widget+0.22.1.patch'); +const provider = 'node_modules/react-native-android-widget/android/src/main/java/com/reactnativeandroidwidget/RNWidgetProvider.java'; + +// The library's own openUri, as published: what the patch is applied to. +const UPSTREAM_OPEN_URI = [ + ' private void openUri(Context context, String uri) {', + ' try {', + ' Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));', + ' intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);', + ' context.startActivity(intent);', + ' } catch (Exception e) {', + ' e.printStackTrace();', + ' }', + ' }', +]; + +describe('a tap that opens the app from a widget', () => { + it('goes through the library’s OPEN_URI, which the patch makes explicit', () => { + expect(open(links.inbox())).toEqual({ clickAction: 'OPEN_URI', clickActionData: { uri: 'bulwarkmobile://mail/folder/inbox' } }); + }); + + it('is sent to this app’s own package, so no chooser offers another build', async () => { + const { parsePatchFile } = await import(path.join(root, 'node_modules/patch-package/dist/patch/parse.js')); + const { executeEffects } = await import(path.join(root, 'node_modules/patch-package/dist/patch/apply.js')); + const effects = parsePatchFile(fs.readFileSync(patchFile, 'utf8')) + .filter((e: { path?: string }) => e.path?.endsWith('RNWidgetProvider.java')); + expect(effects).toHaveLength(1); + + // The published file around openUri, padded to its line numbers. + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'widget-patch-')); + const target = path.join(dir, provider); + fs.mkdirSync(path.dirname(target), { recursive: true }); + const lines = Array.from({ length: 131 }, () => '').concat(UPSTREAM_OPEN_URI, ['', '}']); + fs.writeFileSync(target, lines.join('\n')); + const cwd = process.cwd(); + try { + process.chdir(dir); + executeEffects(effects, { dryRun: false }); + } finally { + process.chdir(cwd); + } + const patched = fs.readFileSync(target, 'utf8'); + const openUri = patched.slice(patched.indexOf('private void openUri'), patched.indexOf('startActivity')); + expect(openUri).toMatch(/intent\.setPackage\(context\.getPackageName\(\)\);/); + fs.rmSync(dir, { recursive: true, force: true }); + }); +});