How to prevent app from subscribing to the same deep link? - java

I've integrated the branch.io in my react-native app, it works on ios but on android every time the app is resumed from the background the branch listener gets triggered, as a result the app receives the previous deep link url and opens it again.
my subscribe function:
branch.subscribe(({error, params, uri}) => {
if (error) {
console.error('Error from Branch: ' + error)
return
}
})
let params = await branch.getLatestReferringParams()
}
this is the params the app receives:
Object {
"+clicked_branch_link": false,
"+is_first_session": false,
"+non_branch_link": "myapp://main/store", }
Has anyone had similar issue with branch on android? I have integrated branch exactly as it's described in the documentation (https://help.branch.io/developers-hub/docs/react-native#section-install-branch).

Related

react native data only fcm on android: start foreground when app is killed

I'm building a react native app which should handle push notifications.
I'm using react-native-notifications to handle the notification logic, and notifee to show the received notifications. But I have a few problems.
There are 3 'states' in which the app is, when a notification should be handled: app in foreground, background or killed.
When the app is in foreground or in background, I can "catch" the notifications with the event handlers from react-native-notifications and based on the payload, create a notification with notifee to display.
The problem is when the app is killed.
I found a pull request of react-native-notifications (see PR here) that would "read" data-only messages on android when the app is killed.
This works, I console.log the output and it shows up in logcat.
My question now is: how can I create a custom notification with notifee when the app is killed? So no react native code can run?
In my index.js I have the following:
AppRegistry.registerHeadlessTask(
"JSNotifyWhenKilledTask",
() => {
return async (notificationBundle) => {
console.log('[JSNotifyWhenKilledTask] notificationBundle', notificationBundle);
}
}
);
the notification is shown in logcat, but now I want to add notifee to this to create a notification. But then I get the following error (in logcat):
android.app.BackgroundServiceStartNotAllowedException: Not allowed to start service Intent
The code that is a problem is this one:
private void notifyReceivedKilledToJS() {
Bundle bundle = new Bundle(mNotificationProps.asBundle());
Intent service = new Intent(mContext.getApplicationContext(), JSNotifyWhenKilledTask.class);
service.putExtras(bundle);
mContext.getApplicationContext().startService(service);
}
I modified the code to this, but now I get another error:
private void notifyReceivedKilledToJS() {
Bundle bundle = new Bundle(mNotificationProps.asBundle());
Intent service = new Intent(mContext.getApplicationContext(), JSNotifyWhenKilledTask.class);
service.putExtras(bundle);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mContext.startForegroundService(new Intent(mContext, JSNotifyWhenKilledTask.class));
} else {
mContext.startService(new Intent(mContext, JSNotifyWhenKilledTask.class));
}
}
android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false
I found this question on SO addressing this problem.
I changed the priority of the notification to "high", and now I get this final error:
android.app.ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground():
I'm guessing I should start this Service.startForeground() somewhere in my java code, but I really have no clue where.
Does anyone know a solution on how to "read" a data-only notification on android when the app is killed, and to run some JS code (notifee) to display a notification?
I'm not very good at java btw, any guidance would be welcome.

How to create a service in native to call a periodic function in flutter

I'm having trouble trying to create a background service that sends the current location to my backend, I have a service in flutter that sends every 30 seconds :
locationPingTimer = new Timer.periodic( Duration(seconds: 30), (Timer t) => { location.getLocation().then((LocationData currentLocation) { var locationString = { "latitude": "${currentLocation.latitude}", "longitude": "${currentLocation.longitude}" }; BackEndService.sendCurrentLocation(locationString); }) });
But when the app goes into the background, it fails to play and not keep sending the location. I'm trying to create a background service using: AndroiAlarmeManager. and Cron.
But both fail and are not guaranteed. I tested it with AlarmeManager: it works when I call a print function, but when I call the function that gets the location it just doesn't work.
the workManager only works every 15 minutes and that's not good for my wish. so here's my question: How can I create a service with a timer in native that executes a flutter function every 1 minute using Method channel ?

Java Bot SDK throws 401 error for proactive message

I'm trying to implement a bot to send proactive messages. I made a proof of concept in NodeJS that works:
const { BotFrameworkAdapter } = require('botbuilder');
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
adapter.onTurnError = async (error) => {
console.error(error);
};
const cr = require('./test_cr.json');
adapter.continueConversation(cr, async (turnContext) => {
await turnContext.sendActivity('Node SDK proactive message')
});
Yet when I try to recreate this example using the Java SDK, I get com.microsoft.bot.connector.rest.ErrorResponseException: Status code 401, {"message":"Authorization has been denied for this request."}.
String appId = System.getenv("MicrosoftAppId");
String appPassword = System.getenv("MicrosoftAppPassword");
BotFrameworkAdapter bot = new BotFrameworkAdapter(new SimpleCredentialProvider(appId, appPassword));
ConversationReference cr = mapper.readValue(new File("test_cr.json"), ConversationReference.class);
CompletableFuture<Void> cf = bot.continueConversation(appId, cr, turnContext -> turnContext.sendActivity("Java SDK proactive message").thenApply(resourceResponse -> null));
cf.get();
The conversation reference and app credentials should be the same for both examples. Am I not setting up the Java bot correctly? For reference, I'm using a pretty barebones conversation reference:
{
"channelId":"msteams",
"serviceUrl":"https://smba.trafficmanager.net/amer/",
"conversation":{
"isGroup":true,
"conversationType":"channel",
"tenantId":"xxxxxx",
"id":"xxxxxx"
}
}
It sounds like it could be an issue with BotTrustServiceUrl. I can't explain it but in one of my bots, I had to add this additional code to get proactive messages to work (specifically after a restart). Not sure if this is your same issue but it helped me.
const { MicrosoftAppCredentials } = require('botframework-connector');
// Then in your proactive message section...
const conversationReference = req.body.conversationReference;
await adapter.continueConversation(conversationReference, async turnContext => {
// If you encounter permission-related errors when sending this message, see
// https://aka.ms/BotTrustServiceUrl
MicrosoftAppCredentials.trustServiceUrl(conversationReference.serviceUrl);
await turnContext.sendActivity(req.body.message);
});
Now I've also got two other bots where I didn't need to do this. The one that isn't working wihtout this code is using an older SDK so that could be it, both otherwise the proactive message functions are identical so I'm not sure.
EDIT: I misread the question and didn't notice that you were having trouble with Java SDK, not JavaScript SDK. But perhaps you could use the same method to see if this resolves your issue in Java as well.

In-App Review calls Log but does not initiate a dialog

I have a situation where I use this method to call a dialog for the In-App Review, but the dialog does not appear either when the test version is an app, or when the app is live in the Play store. However, LogCat Info shows that the method is called properly when the code is called. Can anyone help with advice or suggestion, thanks.
https://developer.android.com/guide/playcore/in-app-review
Gradle
implementation 'com.google.android.play:core:1.8.0'
onCreate
Log.i("rate", "CALL MANAGER");
askRatings();
Code
void askRatings() {
ReviewManager manager = ReviewManagerFactory.create(this);
com.google.android.play.core.tasks.Task<ReviewInfo> request = manager.requestReviewFlow();
request.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
// We can get the ReviewInfo object
ReviewInfo reviewInfo = task.getResult();
Log.i("rate", "SUCCESS FLOW");
com.google.android.play.core.tasks.Task<Void> flow = manager.launchReviewFlow(this, reviewInfo);
flow.addOnCompleteListener(task2 -> {
// The flow has finished. The API does not indicate whether the user
// reviewed or not, or even whether the review dialog was shown. Thus, no
// matter the result, we continue our app flow.
});
} else {
Log.i("rate", "NOT A SUCCESS FLOW");
}
});
}
Log
2020-08-18 11:17:03.641 13328-13328/my.app I/rate: CALL MANAGER
2020-08-18 11:17:03.764 13328-13328/my.app I/rate: SUCCESS FLOW
I had to use the Internal App Sharing and an Android 10 emulator to see the dialog. In Android 9 and previous I see the same logs as you do, but no review pops up. Anyway, I do see a glitch with the android virtual buttons menu appearing for a second, so I believe that means the flow is working.

Cordova - Retrieve local storage from Push Plugin java files

I am programming a mobile app using Cordova. I am implementing the push notifications using Push Plugin. The app is meant to run on all platforms but right now I am testing on Android and Windows.
In a particular javascript file I am saving a value call it 'category' in the localstorage:
localStorage.setItem("category", JSON.stringify(categoryarray));
Now when sending a push notification, the category is essential to decide whether to show the notification or not. If a user is subscribed to that particular category, then, the notification is to be shown, otherwise not. For this I simply create a condition and check whether the user has subscribed to the category included in the notification (but this is not really relevant to the point of the question). When the app is running this condition can be handled in javascript. When the app is not running, this is handled in java code:
else {
extras.putBoolean("foreground", false);
// Send a notification if there is a message
if (extras.getString("message") != null && extras.getString("message").length() != 0) {
createNotification(context, extras);
}
}
Now I want to get the value from the local storage at that instance that the notification is being pushed when the app is not running (and be able to check whether the notification should be shown or not).
I came into this link: Android Service reads localStorage?
But it seems to be meant for Android native code (reference to the webview). Apart from that I haven't really understood how it works and furthermore if it is applicable for my problem.
What do you suggest? How can I do it?
Edit: I didn't initially realise that the Push plugin java code won't be compiled with the Cordova app. So editing the code that is retrievable from the Cordova directory is in reality useless. Unless, someone can still suggest something, I know that this is an unanswerable question. Will have to re-attempt to create an API for this purpose and handle who to receive which notification at server side! (The reason why I resorted to this method was because I wasn't managing to create an API for notification purposes)
I didn't initially realise that the Push plugin java code won't be compiled with the Cordova app. So editing the code that is retrievable from the Cordova directory is in reality useless. Unless, someone can still suggest something, I know that this is an unanswerable question.
This isn't true, Cordova plugin code is compiled when you compile your Cordova app. All Cordova plugin's provide native source code that gets compiled into the app when you run cordova build (or cordova run <platform>).
If you wanted to solve this completely on the client side (rather than managing the categories that a user is subscribed to on the backend and only sending a notification if the user is subscribed to a category), you could extend the PushPlugin to manage subscriptions to categories.
As a rough sketch:
In PushNotification.js, add a method to subscribe to a channel:
PushNotification.prototype.subscribeToChannel(successCallback, errorCallback, channel) {
cordova.exec(successCallback, errorCallback, "PushPlugin", "subscribeToChannel", [{channel: channel}]);
}
In PushPlugin.java catch the subscribeToChannel action in the execute function:
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
...
if ("subscribeToChannel".equals(action)) {
//get the attached data
JSONObject jo = data.getJSONObject(0);
String channel = (String) jo.get("channel");
addChannelToSubscriptions(channel);
}
...
}
public void addChannelToSubscriptions(String channel) {
//store as a list in a sharedpreferences list
}
Then when a notification is received, you can check if the channel is a channel that has been subscribed to.
// Send a notification if subscribed to the channel
if (extras.getString("channel") != null && isSubscribedTo(extras.getString("channel"))) {
createNotification(context, extras);
}
public boolean isSubscribedTo(String channel) {
//see if the channel is in the shared preferences.
}
Personally, I think it'd be easier to manage subscriptions on the backend as to manage it in the app, you'd have to implement this logic for each platform you support. It would be easier to just add a webservice call in your Javascript. As a further alternative, if you don't want to handle the subscription logic on your backend, you could look at a service like Parse where the concept of subscribing to channels is built into the service.

Categories