Skip to content

Commit 30d5971

Browse files
Merge pull request #29 from comapi/dev
Deep links support for latest Android OS
2 parents 09ce15d + 77c8309 commit 30d5971

21 files changed

+187
-988
lines changed

COMAPI/foundation/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ dependencies {
6767

6868
ext {
6969
PUBLISH_GROUP_ID = 'com.comapi'
70-
PUBLISH_VERSION = '1.4.0'
70+
PUBLISH_VERSION = '1.5.0'
7171
PUBLISH_ARTIFACT_ID = 'foundation'
7272
}
7373

COMAPI/foundation/src/main/AndroidManifest.xml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
<!-- SDK will receive a notification when phone finish booting. This is to restore the services and keep SDK responsive -->
3333
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
3434

35+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
36+
3537
<application>
3638

3739
<!-- Broadcast receiver for boot completed broadcasts to resume work after device restart. -->
@@ -45,9 +47,6 @@
4547
</intent-filter>
4648
</receiver>
4749

48-
<receiver android:name="com.comapi.internal.receivers.NotificationClickReceiver"
49-
android:exported="false"/>
50-
5150
<!-- Service to handle Instance ID service token refresh notifications for FCM security. -->
5251
<service
5352
android:name="com.comapi.internal.push.IDService"

COMAPI/foundation/src/main/java/com/comapi/BaseClient.java

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@
2121
package com.comapi;
2222

2323
import android.app.Application;
24+
import android.content.ActivityNotFoundException;
2425
import android.content.Context;
26+
import android.content.Intent;
27+
import android.net.Uri;
2528
import android.os.Handler;
2629
import android.os.Looper;
27-
import androidx.annotation.NonNull;
2830
import android.text.TextUtils;
2931
import android.util.Pair;
3032

33+
import androidx.annotation.NonNull;
34+
3135
import com.comapi.internal.CallbackAdapter;
3236
import com.comapi.internal.ComapiException;
3337
import com.comapi.internal.IClient;
@@ -46,7 +50,12 @@
4650
import com.comapi.internal.network.SessionCreateManager;
4751
import com.comapi.internal.network.api.RestApi;
4852
import com.comapi.internal.network.sockets.SocketController;
53+
import com.comapi.internal.push.PushDataKeys;
4954
import com.comapi.internal.push.PushManager;
55+
import com.google.firebase.messaging.RemoteMessage;
56+
57+
import org.json.JSONException;
58+
import org.json.JSONObject;
5059

5160
import java.io.File;
5261
import java.util.concurrent.CopyOnWriteArrayList;
@@ -214,8 +223,6 @@ restApi, new Handler(mainLooper),
214223
lifecycleListeners.add(socketController.createLifecycleListener());
215224
initialiseLifecycleObserver(application);
216225

217-
pushMgr.setService(service);
218-
219226
sub.onNext(state.compareAndSet(GlobalState.INITIALISING, GlobalState.INITIALISED));
220227
sub.onCompleted();
221228

@@ -407,4 +414,83 @@ public void addListener(StateListener listener) {
407414
public void removeListener(StateListener listener) {
408415
listenerListAdapter.removeListener(listener);
409416
}
417+
418+
protected Observable<PushHandleResult> handlePush(Context activityContext, Intent i, boolean startActivity) {
419+
if (i.hasExtra(PushDataKeys.KEY_PUSH_DEEP_LINK)) {
420+
JSONObject deepLinkData;
421+
try {
422+
deepLinkData = new JSONObject((String) i.getSerializableExtra(PushDataKeys.KEY_PUSH_DEEP_LINK));
423+
if (deepLinkData.has(PushDataKeys.KEY_PUSH_URL)) {
424+
String url = deepLinkData.getString(PushDataKeys.KEY_PUSH_URL);
425+
Observable<Boolean> tracking;
426+
if (deepLinkData.has(PushDataKeys.KEY_PUSH_TRACKING_URL)) {
427+
String trackingUrl = deepLinkData.getString(PushDataKeys.KEY_PUSH_TRACKING_URL);
428+
tracking = service.sendClickData(trackingUrl);
429+
} else {
430+
tracking = Observable.fromCallable(() -> false);
431+
}
432+
return Observable.fromCallable(() -> {
433+
if (startActivity) {
434+
Intent intent = new Intent();
435+
intent.setData(Uri.parse(url));
436+
intent.setAction(Intent.ACTION_VIEW);
437+
intent.addCategory(Intent.CATEGORY_DEFAULT);
438+
intent.addCategory(Intent.CATEGORY_BROWSABLE);
439+
try {
440+
activityContext.startActivity(intent);
441+
return true;
442+
} catch (ActivityNotFoundException e) {
443+
return false;
444+
}
445+
} else {
446+
return false;
447+
}
448+
449+
}).flatMap(isStartActivitySuccessful -> tracking.map(isTrackingSuccessful -> new PushHandleResult(url, null, isTrackingSuccessful, isStartActivitySuccessful)));
450+
}
451+
} catch (Exception e) {
452+
log.f(e.getMessage(), e);
453+
return Observable.error(e);
454+
}
455+
} else if (i.hasExtra(PushDataKeys.KEY_PUSH_DATA)) {
456+
try {
457+
JSONObject data = new JSONObject((String) i.getSerializableExtra(PushDataKeys.KEY_PUSH_DATA));
458+
return Observable.fromCallable(() -> new PushHandleResult(null, data, false, false));
459+
} catch (Exception e) {
460+
return Observable.error(e);
461+
}
462+
}
463+
464+
return Observable.fromCallable(() -> new PushHandleResult(null, null, false, false));
465+
}
466+
467+
/**
468+
* Parse Firebase Push RemoteNotification to extract deep link url or data send with Dotdigital program
469+
* @param message RemoteMessage received in a push handler implementing PushMessageListener registered with SDK initialisation call.
470+
* @return parsed deep link url or data
471+
*/
472+
static public PushDetails parsePushMessage(RemoteMessage message) throws JSONException {
473+
RemoteMessage.Notification n = message.getNotification();
474+
if (message.getData().containsKey(PushDataKeys.KEY_PUSH_DEEP_LINK)) {
475+
String deepLinkDataJson = message.getData().get(PushDataKeys.KEY_PUSH_DEEP_LINK);
476+
if (deepLinkDataJson != null) {
477+
JSONObject deepLinkData = new JSONObject(deepLinkDataJson);
478+
if (deepLinkData.has(PushDataKeys.KEY_PUSH_URL)) {
479+
String url = deepLinkData.getString(PushDataKeys.KEY_PUSH_URL);
480+
return new PushDetails(url, null);
481+
}
482+
} else {
483+
return new PushDetails(null, null);
484+
}
485+
} else if (message.getData().containsKey(PushDataKeys.KEY_PUSH_DATA)) {
486+
String dataJson = message.getData().get(PushDataKeys.KEY_PUSH_DATA);
487+
if (dataJson != null) {
488+
JSONObject data = new JSONObject(dataJson);
489+
return new PushDetails(null, data);
490+
} else {
491+
return new PushDetails(null, null);
492+
}
493+
}
494+
return new PushDetails(null, null);
495+
}
410496
}

COMAPI/foundation/src/main/java/com/comapi/BaseComapi.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class BaseComapi {
3838
/**
3939
* Version of the ComapiImpl SDK MAJOR.MINOR.PATCH.BUILD
4040
*/
41-
private final static String SDK_VERSION = "1.4.0";
41+
private final static String SDK_VERSION = "1.5.0";
4242

4343
private static final Set<String> apiSpaces = Collections.synchronizedSet(new HashSet<String>());
4444

COMAPI/foundation/src/main/java/com/comapi/ComapiClient.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222

2323
import android.app.Application;
2424
import android.content.Context;
25+
import android.content.Intent;
26+
2527
import androidx.annotation.NonNull;
28+
import androidx.annotation.Nullable;
2629

2730
import com.comapi.internal.CallbackAdapter;
2831

@@ -110,4 +113,19 @@ public void copyLogs(@NonNull File file, Callback<File> callback) {
110113
public void clean(@NonNull Context context) {
111114
super.clean(context);
112115
}
116+
117+
/**
118+
* Handles click push notification tracking and opens deep link
119+
* @param activityContext pass calling activity here
120+
* @param i intent that is retrieved by getIntent() in onCreate or intent passed to onNewIntent lifecycle callbacks
121+
* @param startActivity should start activity from deep link url
122+
* @param callback Contains result of the push notification processing
123+
* getUrl - url passed as a deep link with the notification by dotdigital program
124+
* getData - data passed with the notification by dotdigital program
125+
* isTrackingSuccessful - was call to record a click for analytics successful;
126+
* isStartActivitySuccessful - was starting activity from url successful
127+
*/
128+
public void handlePushNotification(@NonNull Context activityContext, @NonNull Intent i, boolean startActivity, @Nullable Callback<PushHandleResult> callback) {
129+
adapter.adapt(super.handlePush(activityContext, i, startActivity),callback);
130+
}
113131
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.comapi;
2+
3+
import androidx.annotation.Nullable;
4+
5+
import org.json.JSONObject;
6+
7+
public class PushDetails {
8+
9+
@Nullable
10+
private final String url;
11+
@Nullable
12+
private final JSONObject data;
13+
14+
public PushDetails(@Nullable String url, @Nullable JSONObject data) {
15+
this.url = url;
16+
this.data = data;
17+
}
18+
19+
@Nullable
20+
public String getUrl() {
21+
return url;
22+
}
23+
24+
@Nullable
25+
public JSONObject getData() {
26+
return data;
27+
}
28+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.comapi;
2+
3+
import androidx.annotation.Nullable;
4+
5+
import org.json.JSONObject;
6+
7+
public class PushHandleResult extends PushDetails {
8+
9+
private final boolean isClickRecorded;
10+
private final boolean isDeepLinkCalled;
11+
12+
public PushHandleResult(@Nullable String url, @Nullable JSONObject data, boolean isClickRecorded, boolean isDeepLinkCalled) {
13+
super(url, data);
14+
this.isClickRecorded = isClickRecorded;
15+
this.isDeepLinkCalled = isDeepLinkCalled;
16+
}
17+
18+
public boolean isClickRecorded() {
19+
return isClickRecorded;
20+
}
21+
22+
public boolean isDeepLinkCalled() {
23+
return isDeepLinkCalled;
24+
}
25+
}

COMAPI/foundation/src/main/java/com/comapi/RxComapiClient.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import android.app.Application;
2424
import android.content.Context;
25+
import android.content.Intent;
26+
2527
import androidx.annotation.NonNull;
2628

2729
import com.comapi.internal.CallbackAdapter;
@@ -137,4 +139,19 @@ void addLifecycleListener(LifecycleListener listener) {
137139
protected RxComapiService getComapiService() {
138140
return service;
139141
}
142+
143+
/**
144+
* Handles click push notification tracking and opens deep link
145+
* @param activityContext pass calling activity here
146+
* @param i intent that is retrieved by getIntent() in onCreate or intent passed to onNewIntent lifecycle callbacks
147+
* @param startActivity should start activity from deep link url
148+
* @return Observable containing result of the push notification processing
149+
* getUrl - url passed as a deep link with the notification
150+
* getData - data passed with the notification by dotdigital program
151+
* isTrackingSuccessful - was call to record a click for analytics successful;
152+
* isStartActivitySuccessful - was starting activity from url successful
153+
*/
154+
public Observable<PushHandleResult> handlePushNotification(Context activityContext, Intent i, boolean startActivity) {
155+
return super.handlePush(activityContext, i, startActivity);
156+
}
140157
}

COMAPI/foundation/src/main/java/com/comapi/internal/IClient.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package com.comapi.internal;
2222

2323
import android.content.Context;
24+
2425
import androidx.annotation.NonNull;
2526

2627
import com.comapi.ComapiClient;

COMAPI/foundation/src/main/java/com/comapi/internal/push/Action.java

Lines changed: 0 additions & 33 deletions
This file was deleted.

COMAPI/foundation/src/main/java/com/comapi/internal/push/ChannelData.java

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)