Create custom Intent
Thanks to the great library, it has greatly simplified and increased the development speed of many applications!
But because we support many applications, we had a small problem with the click on the widget. Widgets have the same basis and differ due to the provision of Flavors. However, they all have the same package name.
When we configure a widget in Manifest we use it
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.myPackageName.WIDGET_CLICK" />
</intent-filter>
And then myPackageName is used in your library when we make click
Intent intent = new Intent(mContext.getPackageName() + ".WIDGET_CLICK");
Therefore, when we have several applications when clicking on a widget, a pop-up appears and asks us to select an application to launch.
I have an idea.
import com.reactnativeandroidwidget.RNWidgetProvider
class MyWidgetProvider : RNWidgetProvider() {
}
Could we set our variable in the constructor or some other way, which will be used instead of WIDGET_CLICK if it exists?
Why does android show the app chooser if the applications have different package name? Is there a way to force the intent to be handled by a given application?
You mentioned multiple applications, what pattern do you have for the package names of the applications?
Also, what is your clickAction when you get the chooser?
Hello, sorry for the long answer. Yes, you turned out to be right in android/app/build.gradle we set different names for different customers in productFlavors -> flavorName -> applicationId.
Several applications were triggered by clicking because there were problems with deep-link settings. However, there were still problems when several applications of the same customer were assembled for different environments. When updating applications, the widgets were triggered by incorrect updates. In one application, the user was logged in, but in the other not, and the widgets had a conflict.
The problem was completely solved due to the following actions
- Using the library patch-package were made changes
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 889a8b4..bb4a7df 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
@@ -20,6 +20,7 @@ import org.json.JSONObject;
import java.util.concurrent.TimeUnit;
public class RNWidgetProvider extends AppWidgetProvider {
+ protected String click_widget = "WIDGET_CLICK";
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
@@ -210,7 +211,7 @@ public class RNWidgetProvider extends AppWidgetProvider {
.build();
}
- Data data = buildData(context, widgetId, "WIDGET_CLICK", additionalData);
+ Data data = buildData(context, widgetId, this.click_widget, additionalData);
startBackgroundTask(context, data);
}
}
After all the following operations, this may be redundant code, but others may find it useful.
- A script has been created that generates different classes for the widget and different manifests for all flavors in the project
const fs = require('fs')
const path = require('path')
const ejs = require('ejs')
const flavors = ['flavor1', 'flavor2', 'flavor3', 'flavor4']
const envs = ['qa1', 'qa2', 'qa3']
const build_types = ['release', 'debug']
const templatePathManifest = path.join(__dirname, 'templates', 'Manifest.ejs')
const templatePathMyWidgetClass = path.join(__dirname, 'templates', 'MyWidget.ejs')
const templateManifest = fs.readFileSync(templatePathManifest, 'utf8')
const templateMyWidgetClass = fs.readFileSync(templatePathMyWidgetClass, 'utf8')
flavors.forEach(flavor => {
envs.forEach(env => {
// eslint-disable-next-line complexity
build_types.forEach(build_type => {
try {
const envName = env[0].toUpperCase() + env.slice(1)
const folderName = flavor + envName + build_type
const className = `MyWidget${flavor[0].toUpperCase()}${flavor.slice(
1,
)}${env[0].toUpperCase()}${env.slice(1)}${build_type}`
const intentName = `WIDGET_CLICK_${flavor.toUpperCase()}_${env.toUpperCase()}_${build_type.toUpperCase()}`
const outputFlavoursDir = path.join(
__dirname,
'..',
'..',
'android',
'app',
'src',
folderName,
)
const outputManifestPath = path.join(outputFlavoursDir, `AndroidManifest.xml`)
const outputWidgetClassDir = path.join(
outputFlavoursDir,
'java',
'com',
'project',
'widget',
)
const outputWidgetClassPath = path.join(outputWidgetClassDir, `${className}.kt`)
const renderedManifest = ejs.render(templateManifest, { className, intentName })
const renderedWidgetClass = ejs.render(templateMyWidgetClass, { className, intentName })
if (!fs.existsSync(outputFlavoursDir)) {
fs.mkdirSync(outputFlavoursDir, { recursive: true })
}
if (!fs.existsSync(outputWidgetClassDir)) {
fs.mkdirSync(outputWidgetClassDir, { recursive: true })
}
fs.writeFileSync(outputManifestPath, renderedManifest)
fs.writeFileSync(outputWidgetClassPath, renderedWidgetClass)
} catch (e) {
console.log('🚀 ~ file: index.js:78 ~ e:', e)
}
})
})
})
templates/Manifest.ejs
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<receiver
android:name=".widget.<%= className %>"
android:exported="false"
android:label="@string/widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.packagename.<%= intentName %>" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widgetprovider_mywidget" />
</receiver>
</application>
</manifest>
Be careful with packagename
templates/MyWidget.ejs
package com.myprogect.widget
import com.reactnativeandroidwidget.RNWidgetProvider
class <%= className %> : RNWidgetProvider() {
init {
this.click_widget = "<%= intentName %>"
}
}
These changes fixed my problem. A little later I will check whether it is possible to work correctly without using the patch package
I'm not sure I completely understand. You are updating the click_action, but there are also problems with the update?
What is in your clickAction prop when you face this issue?
Can you create an example repo with two apps with conflicting click/update handlers?
I'll close this since it looks like you have a workaround. If you have some time to create a reproducible example feel free to reopen this and I will take a look.