Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
[![npm version](https://img.shields.io/npm/v/cordova-plugin-fcm-with-dependecy-updated.svg)](https://www.npmjs.com/package/cordova-plugin-fcm-with-dependecy-updated)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
[![GitHub issues](https://img.shields.io/github/issues/andrehtissot/cordova-plugin-fcm-with-dependecy-updated.svg)](https://github.com/andrehtissot/cordova-plugin-fcm-with-dependecy-updated/issues)
[![GitHub forks](https://img.shields.io/github/forks/andrehtissot/cordova-plugin-fcm-with-dependecy-updated.svg)](https://github.com/andrehtissot/cordova-plugin-fcm-with-dependecy-updated/network)
[![GitHub stars](https://img.shields.io/github/stars/andrehtissot/cordova-plugin-fcm-with-dependecy-updated.svg)](https://github.com/andrehtissot/cordova-plugin-fcm-with-dependecy-updated/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/andrehtissot/cordova-plugin-fcm-with-dependecy-updated.svg)](https://github.com/marutifh/cordova-plugin-fcm-with-dependecy-updated/network)
[![GitHub stars](https://img.shields.io/github/stars/andrehtissot/cordova-plugin-fcm-with-dependecy-updated.svg)](https://github.com/marutifh/cordova-plugin-fcm-with-dependecy-updated/stargazers)
[![Known Vulnerabilities](https://snyk.io/test/github/andrehtissot/cordova-plugin-fcm-with-dependecy-updated/badge.svg?targetFile=package.json)](https://snyk.io/test/github/andrehtissot/cordova-plugin-fcm-with-dependecy-updated?targetFile=package.json)
[![DeepScan grade](https://deepscan.io/api/teams/3417/projects/5068/branches/39495/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=3417&pid=5068&bid=39495)

Expand Down Expand Up @@ -50,8 +50,8 @@ Make sure you have ‘google-services.json’ for Android and/or ‘GoogleServic
|Preference|Default Value|Description|
|---|---|---|
|ANDROID_DEFAULT_NOTIFICATION_ICON|@mipmap/ic_launcher|Default notification icon.|
|ANDROID_FCM_VERSION|21.0.0|Native Firebase Message SDK version.<br>:warning: Replaced by BoM versioning on Gradle >= 3.4.|
|ANDROID_FIREBASE_BOM_VERSION|26.0.0|[Firebase BoM](https://firebase.google.com/docs/android/learn-more#bom) version.|
|ANDROID_FCM_VERSION|23.0.0|Native Firebase Message SDK version.<br>:warning: Replaced by BoM versioning on Gradle >= 3.4.|
|ANDROID_FIREBASE_BOM_VERSION|29.0.1|[Firebase BoM](https://firebase.google.com/docs/android/learn-more#bom) version.|
|ANDROID_GOOGLE_SERVICES_VERSION|4.3.4|Native Google Services SDK version.|
|ANDROID_GRADLE_TOOLS_VERSION|4.1.0|Gradle tools version.|
|IOS_FIREBASE_MESSAGING_VERSION|~> 7.4.0|Native Firebase Message SDK version|
Expand Down
9 changes: 5 additions & 4 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,21 @@
<!-- ANDROID CONFIGURATION -->
<platform name="android">
<preference name="ANDROID_DEFAULT_NOTIFICATION_ICON" default="@mipmap/ic_launcher" />
<preference name="ANDROID_FCM_VERSION" default="21.0.0" />
<preference name="ANDROID_FIREBASE_BOM_VERSION" default="26.0.0" />
<preference name="ANDROID_FCM_VERSION" default="23.0.8" />
<preference name="ANDROID_FIREBASE_BOM_VERSION" default="29.0.1" />
<preference name="ANDROID_GOOGLE_SERVICES_VERSION" default="4.3.4" />
<preference name="ANDROID_GRADLE_TOOLS_VERSION" default="4.1.0" />

<config-file target="AndroidManifest.xml" parent="/manifest/application">
<activity android:name="com.gae.scaffolder.plugin.FCMPluginActivity" android:launchMode="singleTop">
<activity android:name="com.gae.scaffolder.plugin.FCMPluginActivity" android:exported="true" android:launchMode="singleTop">
<intent-filter>
<action android:name="FCM_PLUGIN_ACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name="com.gae.scaffolder.plugin.MyFirebaseMessagingService"
android:name="com.gae.scaffolder.plugin.MyFirebaseMessagingService"
android:exported="false"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
Expand Down
140 changes: 131 additions & 9 deletions src/android/com/gae/scaffolder/plugin/FCMPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import androidx.core.app.NotificationManagerCompat;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;

import com.gae.scaffolder.plugin.interfaces.*;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
import com.google.firebase.messaging.FirebaseMessaging;

import org.apache.cordova.CallbackContext;
Expand All @@ -32,6 +32,10 @@ public class FCMPlugin extends CordovaPlugin {
private static FCMPlugin instance;
protected Context context;
protected static CallbackContext jsEventBridgeCallbackContext;
protected static final String POST_NOTIFICATIONS = "POST_NOTIFICATIONS";
protected static final int POST_NOTIFICATIONS_PERMISSION_REQUEST_ID = 1;

private static CallbackContext postNotificationPermissionRequestCallbackContext;

public FCMPlugin() {}
public FCMPlugin(Context context) {
Expand Down Expand Up @@ -140,6 +144,8 @@ public void run() {
this.deleteInstanceId(callbackContext);
} else if (action.equals("hasPermission")) {
this.hasPermission(callbackContext);
} else if (action.equals("requestPushPermission")) {
this.grantPermission(callbackContext);
} else {
callbackContext.error("Method not found");
return false;
Expand Down Expand Up @@ -179,9 +185,9 @@ public void getInitialPushPayload(CallbackContext callback) {

public void getToken(final TokenListeners<String, JSONObject> callback) {
try {
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener<String>() {
@Override
public void onComplete(Task<InstanceIdResult> task) {
public void onComplete(Task<String> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
try {
Expand All @@ -194,14 +200,14 @@ public void onComplete(Task<InstanceIdResult> task) {
}

// Get new Instance ID token
String newToken = task.getResult().getToken();
String newToken = task.getResult();

Log.i(TAG, "\tToken: " + newToken);
callback.success(newToken);
}
});

FirebaseInstanceId.getInstance().getInstanceId().addOnFailureListener(new OnFailureListener() {
FirebaseMessaging.getInstance().getToken().addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(final Exception e) {
try {
Expand All @@ -224,7 +230,7 @@ private void deleteInstanceId(final CallbackContext callbackContext) {
cordova.getThreadPool().execute(new Runnable() {
public void run() {
try {
FirebaseInstanceId.getInstance().deleteInstanceId();
FirebaseMessaging.getInstance().deleteToken();
callbackContext.success();
} catch (Exception e) {
callbackContext.error(e.getMessage());
Expand All @@ -238,15 +244,131 @@ private void hasPermission(final CallbackContext callbackContext) {
public void run() {
try {
NotificationManagerCompat notificationManagerCompat =
NotificationManagerCompat.from(cordova.getActivity().getApplicationContext());
callbackContext.success(notificationManagerCompat.areNotificationsEnabled() ? 1 : 0);
NotificationManagerCompat.from(cordova.getActivity().getApplicationContext());

boolean areNotificationsEnabled = notificationManagerCompat.areNotificationsEnabled();

boolean hasRuntimePermission;

if (Build.VERSION.SDK_INT >= 33) { // Android 13+
hasRuntimePermission = hasRuntimePermission(POST_NOTIFICATIONS);
} else {
hasRuntimePermission = true;
}

callbackContext.success(areNotificationsEnabled && hasRuntimePermission ? 1 : 0);
} catch (Exception e) {
callbackContext.error(e.getMessage());
}
}
});
}

private void grantPermission(final CallbackContext callbackContext) {
CordovaPlugin plugin = this;
cordova.getThreadPool().execute(new Runnable() {
public void run() {
try {
if (Build.VERSION.SDK_INT >= 33) { // Android 13+
boolean hasRuntimePermission = hasRuntimePermission(POST_NOTIFICATIONS);
if (hasRuntimePermission) {
callbackContext.success(1);
}
else {
String[] permissions = new String[]{qualifyPermission(POST_NOTIFICATIONS)};
postNotificationPermissionRequestCallbackContext = callbackContext;
requestPermissions(plugin, POST_NOTIFICATIONS_PERMISSION_REQUEST_ID, permissions);
sendEmptyPluginResultAndKeepCallback(callbackContext);
}
} else {
callbackContext.success(1);
}

} catch (Exception e) {
callbackContext.error(e.getMessage());
}
}
});
}

protected void sendEmptyPluginResultAndKeepCallback(CallbackContext callbackContext) {
PluginResult pluginresult = new PluginResult(PluginResult.Status.NO_RESULT);
pluginresult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginresult);
}

protected String qualifyPermission(String permission) {
if (permission.startsWith("android.permission.")) {
return permission;
} else {
return "android.permission." + permission;
}
}

protected boolean hasRuntimePermission(String permission) throws Exception {
boolean hasRuntimePermission = true;
String qualifiedPermission = qualifyPermission(permission);
java.lang.reflect.Method method = null;
try {
method = cordova.getClass().getMethod("hasPermission", qualifiedPermission.getClass());
Boolean bool = (Boolean) method.invoke(cordova, qualifiedPermission);
hasRuntimePermission = bool.booleanValue();
} catch (NoSuchMethodException e) {
Log.w(TAG, "Cordova v" + CordovaWebView.CORDOVA_VERSION + " does not support runtime permissions so defaulting to GRANTED for " + permission);
}
return hasRuntimePermission;
}

protected void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) throws Exception {
try {
java.lang.reflect.Method method = cordova.getClass().getMethod("requestPermissions", org.apache.cordova.CordovaPlugin.class, int.class, java.lang.String[].class);
method.invoke(cordova, plugin, requestCode, permissions);
} catch (NoSuchMethodException e) {
throw new Exception("requestPermissions() method not found in CordovaInterface implementation of Cordova v" + CordovaWebView.CORDOVA_VERSION);
}
}

/************
* Overrides
***********/

/**
* then updates the list of status based on the grantResults before passing the result back via the context.
*
* @param requestCode - ID that was used when requesting permissions
* @param permissions - list of permissions that were requested
* @param grantResults - list of flags indicating if above permissions were granted or denied
*/
public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException {
String sRequestId = String.valueOf(requestCode);
Log.v(TAG, "Received result for permissions request id=" + sRequestId);
try {
if (postNotificationPermissionRequestCallbackContext == null) {
Log.e(TAG, "No callback context found for permissions request id=" + sRequestId);
return;
}

boolean postNotificationPermissionGranted = false;
for (int i = 0, len = permissions.length; i < len; i++) {
String androidPermission = permissions[i];

if (androidPermission.equals(qualifyPermission(POST_NOTIFICATIONS))) {
postNotificationPermissionGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
}
}

postNotificationPermissionRequestCallbackContext.success(postNotificationPermissionGranted ? 1 : 0);
postNotificationPermissionRequestCallbackContext = null;

} catch (Exception e) {
if (postNotificationPermissionRequestCallbackContext != null) {
postNotificationPermissionRequestCallbackContext.error(e.getMessage());
} else {
Log.e(TAG, "onRequestPermissionResult error " + e.getMessage());
}
}
}

private JSONObject exceptionToJson(final Exception exception) throws JSONException {
return new JSONObject() {
{
Expand Down
66 changes: 39 additions & 27 deletions src/android/com/gae/scaffolder/plugin/FCMPluginActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,22 @@ public class FCMPluginActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "==> FCMPluginActivity onCreate");
this.sendPushPayload();
handleNotification(this, getIntent());
finish();
forceMainActivityReload();
}

private void sendPushPayload() {
Bundle intentExtras = getIntent().getExtras();
if(intentExtras == null) {
return;
}
Log.d(TAG, "==> USER TAPPED NOTIFICATION");
Map<String, Object> data = new HashMap<String, Object>();
data.put("wasTapped", true);
for (String key : intentExtras.keySet()) {
Object value = intentExtras.get(key);
Log.d(TAG, "\tKey: " + key + " Value: " + value);
data.put(key, value);
}
FCMPlugin.setInitialPushPayload(data);
FCMPlugin.sendPushPayload(data);
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d(TAG, "==> FCMPluginActivity onNewIntent");
handleNotification(this, intent);
finish();
}

private void forceMainActivityReload() {
PackageManager pm = getPackageManager();
Intent launchIntent = pm.getLaunchIntentForPackage(getApplicationContext().getPackageName());
startActivity(launchIntent);
@Override
public void onStart() {
super.onStart();
Log.d(TAG, "==> FCMPluginActivity onStart");
}

@Override
Expand All @@ -60,16 +50,38 @@ protected void onResume() {
notificationManager.cancelAll();
}

@Override
public void onStart() {
super.onStart();
Log.d(TAG, "==> FCMPluginActivity onStart");
}

@Override
public void onStop() {
super.onStop();
Log.d(TAG, "==> FCMPluginActivity onStop");
}

private static void handleNotification(Context context, Intent intent) {
try {
PackageManager packageManager = context.getPackageManager();

Intent launchIntent = packageManager.getLaunchIntentForPackage(context.getPackageName());
launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);

Bundle intentExtras = intent.getExtras();
if (intentExtras == null) {
return;
}
Log.d(TAG, "==> USER TAPPED NOTIFICATION " + intentExtras.toString());
Map<String, Object> data = new HashMap<String, Object>();
data.put("wasTapped", true);
for (String key : intentExtras.keySet()) {
Object value = intentExtras.get(key);
Log.d(TAG, "\tKey: " + key + " Value: " + value);
data.put(key, value);
}
FCMPlugin.setInitialPushPayload(data);
FCMPlugin.sendPushPayload(data);

launchIntent.putExtras(intentExtras);
context.startActivity(launchIntent);
} catch (Exception e) {
Log.e(TAG, "handleNotification error " + e.getMessage());
}
}
}
3 changes: 0 additions & 3 deletions www/FCMPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ var FCMPlugin = (function () {
};
FCMPlugin.prototype.requestPushPermission = function (options) {
var _a, _b, _c, _d;
if (window.cordova.platformId !== 'ios') {
return Promise.resolve(true);
}
var ios9SupportTimeout = (_b = (_a = options === null || options === void 0 ? void 0 : options.ios9Support) === null || _a === void 0 ? void 0 : _a.timeout) !== null && _b !== void 0 ? _b : 10;
var ios9SupportInterval = (_d = (_c = options === null || options === void 0 ? void 0 : options.ios9Support) === null || _c === void 0 ? void 0 : _c.interval) !== null && _d !== void 0 ? _d : 0.3;
return execAsPromise('requestPushPermission', [ios9SupportTimeout, ios9SupportInterval]);
Expand Down