Skip to content

Commit 374ba76

Browse files
committed
Added support for the FCM library
* Added support to use the Firebase FCM library * GCM can still be used if the app developer hasn't updated yet * Preventing multiple FCM/GCM registration threads from running * Added warning to the logcat if GCM is still included in the app project * Refactored library checks and registration code.
1 parent e5e6605 commit 374ba76

20 files changed

+548
-325
lines changed

OneSignalSDK/onesignal/build.gradle

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,21 @@ android {
2525
}
2626
}
2727

28+
// api || implementation = compile and runtime
29+
2830
dependencies {
29-
provided fileTree(dir: 'libs', include: ['*.jar'])
31+
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
32+
33+
compileOnly 'com.google.android.gms:play-services-gcm:12.0.1'
34+
api 'com.google.firebase:firebase-messaging:12.0.1'
3035

31-
api 'com.google.android.gms:play-services-gcm:12.0.1'
3236
implementation 'com.google.android.gms:play-services-location:12.0.1'
3337

3438
api 'com.android.support:support-v4:27.1.1'
3539
api 'com.android.support:customtabs:27.1.1'
40+
41+
// Change api to implementation. Need to check however this has any effect in production
42+
// projects that pull from maven.
3643
}
3744

3845
apply from: 'maven-push.gradle'

OneSignalSDK/onesignal/maven-push.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Global {
2929
// Limit upper number (exclusive) to prevent untested versions
3030
static def versionGroupOverrides = [
3131
'com.google.android.gms': '[10.2.1, 12.1.0)',
32+
'com.google.firebase': '[10.2.1, 12.1.0)',
3233
'com.android.support': '[26.0.0, 27.2.0)'
3334
]
3435

OneSignalSDK/onesignal/src/main/java/com/onesignal/GcmBroadcastReceiver.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Modified MIT License
33
*
4-
* Copyright 2017 OneSignal
4+
* Copyright 2018 OneSignal
55
*
66
* Permission is hereby granted, free of charge, to any person obtaining a copy
77
* of this software and associated documentation files (the "Software"), to deal
@@ -42,6 +42,8 @@
4242

4343
import java.util.Random;
4444

45+
// This is the entry point when a FCM / GCM payload is received from the Google Play services app
46+
// TODO: 4.0.0 - Update to use <action android:name="com.google.firebase.MESSAGING_EVENT"/>
4547
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
4648

4749
private static final String GCM_RECEIVE_ACTION = "com.google.android.c2dm.intent.RECEIVE";
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package com.onesignal;
2+
3+
import android.app.Activity;
4+
import android.app.AlertDialog;
5+
import android.app.PendingIntent;
6+
import android.content.DialogInterface;
7+
import android.content.pm.PackageInfo;
8+
import android.content.pm.PackageManager;
9+
10+
import com.google.android.gms.common.GoogleApiAvailability;
11+
12+
import static com.onesignal.OSUtils.getResourceString;
13+
14+
class GooglePlayServicesUpgradePrompt {
15+
16+
private static final String GOOGLE_PLAY_SERVICES_PACKAGE_NAME = "com.google.android.gms";
17+
private static final String GOOGLE_PLAY_STORE_PACKAGE_NAME = "com.android.vending";
18+
19+
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
20+
21+
static boolean isGMSInstalledAndEnabled() {
22+
try {
23+
PackageManager pm = OneSignal.appContext.getPackageManager();
24+
PackageInfo info = pm.getPackageInfo(GOOGLE_PLAY_SERVICES_PACKAGE_NAME, PackageManager.GET_ACTIVITIES);
25+
26+
return info.applicationInfo.enabled;
27+
} catch (PackageManager.NameNotFoundException e) {}
28+
29+
return false;
30+
}
31+
32+
private static boolean isGooglePlayStoreInstalled() {
33+
try {
34+
PackageManager pm = OneSignal.appContext.getPackageManager();
35+
PackageInfo info = pm.getPackageInfo(GOOGLE_PLAY_STORE_PACKAGE_NAME, PackageManager.GET_ACTIVITIES);
36+
String label = (String) info.applicationInfo.loadLabel(pm);
37+
return (label != null && !label.equals("Market"));
38+
} catch (Throwable e) {}
39+
40+
return false;
41+
}
42+
43+
static void ShowUpdateGPSDialog() {
44+
if (isGMSInstalledAndEnabled() || !isGooglePlayStoreInstalled())
45+
return;
46+
47+
boolean userSelectedSkip =
48+
OneSignalPrefs.getBool(
49+
OneSignalPrefs.PREFS_ONESIGNAL,
50+
OneSignalPrefs.PREFS_GT_DO_NOT_SHOW_MISSING_GPS,
51+
false
52+
);
53+
if (userSelectedSkip)
54+
return;
55+
56+
OSUtils.runOnMainUIThread(new Runnable() {
57+
@Override
58+
public void run() {
59+
final Activity activity = ActivityLifecycleHandler.curActivity;
60+
if (activity == null || OneSignal.mInitBuilder.mDisableGmsMissingPrompt)
61+
return;
62+
63+
// Load resource strings so a developer can customize this dialog
64+
String alertBodyText = getResourceString(activity, "onesignal_gms_missing_alert_text", "To receive push notifications please press 'Update' to enable 'Google Play services'.");
65+
String alertButtonUpdate = getResourceString(activity, "onesignal_gms_missing_alert_button_update", "Update");
66+
String alertButtonSkip = getResourceString(activity, "onesignal_gms_missing_alert_button_skip", "Skip");
67+
String alertButtonClose = getResourceString(activity, "onesignal_gms_missing_alert_button_close", "Close");
68+
69+
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
70+
builder.setMessage(alertBodyText).setPositiveButton(alertButtonUpdate, new DialogInterface.OnClickListener() {
71+
@Override
72+
public void onClick(DialogInterface dialog, int which) {
73+
OpenPlayStoreToApp(activity);
74+
}
75+
}).setNegativeButton(alertButtonSkip, new DialogInterface.OnClickListener() {
76+
@Override
77+
public void onClick(DialogInterface dialog, int which) {
78+
OneSignalPrefs.saveBool(OneSignalPrefs.PREFS_ONESIGNAL,
79+
OneSignalPrefs.PREFS_GT_DO_NOT_SHOW_MISSING_GPS,true);
80+
81+
}
82+
}).setNeutralButton(alertButtonClose, null).create().show();
83+
}
84+
});
85+
}
86+
87+
// Take the user to the Google Play store to update or enable the Google Play Services app
88+
private static void OpenPlayStoreToApp(Activity activity) {
89+
try {
90+
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
91+
int resultCode = apiAvailability.isGooglePlayServicesAvailable(OneSignal.appContext);
92+
// Send the Intent to trigger opening the store
93+
apiAvailability.getErrorResolutionPendingIntent(
94+
activity,
95+
resultCode,
96+
PLAY_SERVICES_RESOLUTION_REQUEST
97+
).send();
98+
} catch (PendingIntent.CanceledException e) {
99+
} catch (Throwable e) {
100+
e.printStackTrace();
101+
}
102+
}
103+
104+
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSUtils.java

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -70,55 +70,80 @@ int initializationChecker(Context context, int deviceType, String oneSignalAppId
7070
"5eb5a37e-b458-11e3-ac11-000c2940e62c".equals(oneSignalAppId))
7171
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "OneSignal Example AppID detected, please update to your app's id found on OneSignal.com");
7272

73-
if (deviceType == 1) {
74-
try {
75-
Class.forName("com.google.android.gms.gcm.GoogleCloudMessaging");
76-
} catch (ClassNotFoundException e) {
77-
OneSignal.Log(OneSignal.LOG_LEVEL.FATAL, "The GCM Google Play services client library was not found. Please make sure to include it in your project.", e);
78-
subscribableStatus = -4;
79-
}
73+
if (deviceType == UserState.DEVICE_TYPE_ANDROID) {
74+
Integer pushErrorType = checkForGooglePushLibrary();
75+
if (pushErrorType != null)
76+
subscribableStatus = pushErrorType;
77+
}
8078

81-
try {
82-
Class.forName("com.google.android.gms.common.GooglePlayServicesUtil");
83-
} catch (ClassNotFoundException e) {
84-
OneSignal.Log(OneSignal.LOG_LEVEL.FATAL, "The GooglePlayServicesUtil class part of Google Play services client library was not found. Include this in your project.", e);
85-
subscribableStatus = -4;
86-
}
79+
Integer supportErrorType = checkAndroidSupportLibrary(context);
80+
if (supportErrorType != null)
81+
subscribableStatus = supportErrorType;
82+
83+
return subscribableStatus;
84+
}
85+
86+
87+
static boolean hasFCMLibrary() {
88+
return classExists("com.google.firebase.messaging.FirebaseMessaging");
89+
}
90+
91+
static boolean hasGCMLibrary() {
92+
return classExists("com.google.android.gms.gcm.GoogleCloudMessaging");
93+
}
94+
95+
Integer checkForGooglePushLibrary() {
96+
boolean hasFCMLibrary = hasFCMLibrary();
97+
boolean hasGCMLibrary = hasGCMLibrary();
98+
99+
if (!hasFCMLibrary && !hasGCMLibrary) {
100+
OneSignal.Log(OneSignal.LOG_LEVEL.FATAL, "The Firebase FCM library is missing! Please make sure to include it in your project.");
101+
return UserState.PUSH_STATUS_MISSING_FIREBASE_FCM_LIBRARY;
87102
}
88103

89-
try {
90-
Class.forName("android.support.v4.view.MenuCompat");
91-
try {
92-
Class.forName("android.support.v4.content.WakefulBroadcastReceiver");
93-
Class.forName("android.support.v4.app.NotificationManagerCompat");
94-
95-
// If running on Android O and targeting O we need version 26.0.0 for
96-
// the new compat NotificationCompat.Builder constructor.
97-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
98-
&& getTargetSdkVersion(context) >= Build.VERSION_CODES.O) {
99-
// Class was added in 26.0.0-beta2
100-
Class.forName("android.support.v4.app.JobIntentService");
101-
}
102-
} catch (ClassNotFoundException e) {
103-
OneSignal.Log(OneSignal.LOG_LEVEL.FATAL, "The included Android Support Library is to old or incomplete. Please update to the 26.0.0 revision or newer.", e);
104-
subscribableStatus = -5;
104+
if (hasGCMLibrary && !hasFCMLibrary)
105+
OneSignal.Log(OneSignal.LOG_LEVEL.WARN, "GCM Library detected, please upgrade to Firebase FCM library as GCM is deprecated!");
106+
107+
if (hasGCMLibrary && hasFCMLibrary)
108+
OneSignal.Log(OneSignal.LOG_LEVEL.WARN, "Both GCM & FCM Libraries detected! Please remove the deprecated GCM library.");
109+
110+
return null;
111+
}
112+
113+
Integer checkAndroidSupportLibrary(Context context) {
114+
if (!classExists("android.support.v4.view.MenuCompat")) {
115+
OneSignal.Log(OneSignal.LOG_LEVEL.FATAL, "Could not find the Android Support Library. Please make sure it has been correctly added to your project.");
116+
return UserState.PUSH_STATUS_MISSING_ANDROID_SUPPORT_LIBRARY;
117+
}
118+
119+
if (!classExists("android.support.v4.content.WakefulBroadcastReceiver") ||
120+
!classExists("android.support.v4.app.NotificationManagerCompat")) {
121+
OneSignal.Log(OneSignal.LOG_LEVEL.FATAL, "The included Android Support Library is to old or incomplete. Please update to the 26.0.0 revision or newer.");
122+
return UserState.PUSH_STATUS_OUTDATED_ANDROID_SUPPORT_LIBRARY;
123+
}
124+
125+
// If running on Android O and targeting O we need version 26.0.0 for
126+
// the new compat NotificationCompat.Builder constructor.
127+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
128+
&& getTargetSdkVersion(context) >= Build.VERSION_CODES.O) {
129+
// Class was added in 26.0.0-beta2
130+
if (!classExists("android.support.v4.app.JobIntentService")) {
131+
OneSignal.Log(OneSignal.LOG_LEVEL.FATAL, "The included Android Support Library is to old or incomplete. Please update to the 26.0.0 revision or newer.");
132+
return UserState.PUSH_STATUS_OUTDATED_ANDROID_SUPPORT_LIBRARY;
105133
}
106-
} catch (ClassNotFoundException e) {
107-
OneSignal.Log(OneSignal.LOG_LEVEL.FATAL, "Could not find the Android Support Library. Please make sure it has been correctly added to your project.", e);
108-
subscribableStatus = -3;
109134
}
110135

111-
return subscribableStatus;
136+
return null;
112137
}
113138

114139
int getDeviceType() {
115140
try {
116141
// Class only available on the FireOS and only when the following is in the AndroidManifest.xml.
117142
// <amazon:enable-feature android:name="com.amazon.device.messaging" android:required="false"/>
118143
Class.forName("com.amazon.device.messaging.ADM");
119-
return 2;
144+
return UserState.DEVICE_TYPE_FIREOS;
120145
} catch (ClassNotFoundException e) {
121-
return 1;
146+
return UserState.DEVICE_TYPE_ANDROID;
122147
}
123148
}
124149

@@ -292,4 +317,13 @@ static void sleep(int ms) {
292317
e.printStackTrace();
293318
}
294319
}
320+
321+
static boolean classExists(String classWithNamespace) {
322+
try {
323+
Class.forName(classWithNamespace);
324+
return true;
325+
} catch (ClassNotFoundException e) {
326+
return false;
327+
}
328+
}
295329
}

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -749,26 +749,36 @@ public void complete(LocationGMS.LocationPoint point) {
749749
LocationGMS.getLocation(appContext, doPrompt, locationHandler);
750750
}
751751

752-
private static void registerForPushToken() {
753-
PushRegistrator pushRegistrator;
754-
if (deviceType == 2)
755-
pushRegistrator = new PushRegistratorADM();
752+
private static PushRegistrator mPushRegistrator;
753+
private static PushRegistrator getPushRegistrator() {
754+
if (mPushRegistrator != null)
755+
return mPushRegistrator;
756+
757+
if (deviceType == UserState.DEVICE_TYPE_FIREOS)
758+
mPushRegistrator = new PushRegistratorADM();
759+
else if (OSUtils.hasFCMLibrary())
760+
mPushRegistrator = new PushRegistratorFCM();
756761
else
757-
pushRegistrator = new PushRegistratorGPS();
762+
mPushRegistrator = new PushRegistratorGCM();
763+
764+
return mPushRegistrator;
765+
}
758766

759-
pushRegistrator.registerForPush(appContext, mGoogleProjectNumber, new PushRegistrator.RegisteredHandler() {
767+
private static void registerForPushToken() {
768+
getPushRegistrator().registerForPush(appContext, mGoogleProjectNumber, new PushRegistrator.RegisteredHandler() {
760769
@Override
761770
public void complete(String id, int status) {
762-
if (status < 1) {
771+
if (status < UserState.PUSH_STATUS_SUBSCRIBED) {
763772
// Only allow errored subscribableStatuses if we have never gotten a token.
764773
// This ensures the device will not later be marked unsubscribed due to a
765774
// any inconsistencies returned by Google Play services.
766-
// Also do not override other types of errors status ( > -6).
775+
// Also do not override a config error status if we got a runtime error
767776
if (OneSignalStateSynchronizer.getRegistrationId() == null &&
768-
(subscribableStatus == 1 || subscribableStatus < -6))
777+
(subscribableStatus == UserState.PUSH_STATUS_SUBSCRIBED ||
778+
pushStatusRuntimeError(subscribableStatus)))
769779
subscribableStatus = status;
770780
}
771-
else if (subscribableStatus < -6)
781+
else if (pushStatusRuntimeError(subscribableStatus))
772782
subscribableStatus = status;
773783

774784
lastRegistrationId = id;
@@ -779,6 +789,10 @@ else if (subscribableStatus < -6)
779789
});
780790
}
781791

792+
private static boolean pushStatusRuntimeError(int subscribableStatus) {
793+
return subscribableStatus < -6;
794+
}
795+
782796
private static int androidParamsReties = 0;
783797

784798
private static void makeAndroidParamsRequest() {

OneSignalSDK/onesignal/src/main/java/com/onesignal/PushRegistrator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Modified MIT License
33
*
4-
* Copyright 2016 OneSignal
4+
* Copyright 2018 OneSignal
55
*
66
* Permission is hereby granted, free of charge, to any person obtaining a copy
77
* of this software and associated documentation files (the "Software"), to deal
@@ -35,5 +35,5 @@ interface RegisteredHandler {
3535
void complete(String id, int status);
3636
}
3737

38-
void registerForPush(Context context, String googleProjectNumber, RegisteredHandler callback);
38+
void registerForPush(Context context, String senderId, RegisteredHandler callback);
3939
}

0 commit comments

Comments
 (0)