Skip to content
This repository has been archived by the owner on Sep 4, 2020. It is now read-only.

check whether Push Notification Permissions have been enabled for this app #305

Closed
wants to merge 4 commits into from
Closed
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
46 changes: 34 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This requires phonegap/cordova CLI 5.0+ ( current stable v1.4.2 )
```
phonegap plugin add phonegap-plugin-push
```
or
or

```
cordova plugin add phonegap-plugin-push
Expand All @@ -21,7 +21,7 @@ It is also possible to install via repo url directly ( unstable )
phonegap plugin add https://github.com/phonegap/phonegap-plugin-push
```

or
or

```
cordova plugin add https://github.com/phonegap/phonegap-plugin-push
Expand Down Expand Up @@ -202,6 +202,28 @@ successHandler gets called when background push processing is successfully compl
push.finish(successHandler, errorHandler);
```

### PushNotification.hasPermission(callback)

Checks whether the PushNotification Permission have been enabled or disabled.

Callback Parameter | Description
------------------ | -----------
`data.isEnabled` | `Boolean`

#### Example

```javascript
PushNotification.hasPermission(function(data) {
if (data.isEnabled) {
var push = PushNotification.init({
android: {
senderId: 'abc'
}
});
}
});
```

## PhoneGap Build Support

Including this plugin in a project that is built by PhoneGap Build is as easy as adding:
Expand Down Expand Up @@ -246,10 +268,10 @@ This is because Android now uses Material design and the default icon for push w
In order to get a better user experience you can specify an alternate icon and background color to be shown when receiving a push notification. The code would look like this:

```javascript
var push = PushNotification.init({
"android": {
"senderID": "123456789", "icon": "phonegap", "iconColor": "blue"},
"ios": {"alert": "true", "badge": "true", "sound": "true"}, "windows": {}
var push = PushNotification.init({
"android": {
"senderID": "123456789", "icon": "phonegap", "iconColor": "blue"},
"ios": {"alert": "true", "badge": "true", "sound": "true"}, "windows": {}
});
```

Expand Down Expand Up @@ -482,7 +504,7 @@ To add to your app:
```
phonegap plugin add https://github.com/jeduan/cordova-plugin-facebook4 --variable APP_ID="App ID" --variable APP_NAME="App Name"
```
or
or

```
cordova plugin add https://github.com/jeduan/cordova-plugin-facebook4 --variable APP_ID="App ID" --variable APP_NAME="App Name"
Expand Down Expand Up @@ -581,7 +603,7 @@ However if you want your `on('notification')` event handler called but no notifi
}
```

That covers what you need to do on the server side to accept background pushes on iOS. However, it is critically important that you continue reading as there will be a change in your `on('notification')`. When you receive a background push on iOS you will be given 30 seconds of time in which to complete a task. If you spend longer than 30 seconds on the task the OS may decide that your app is misbehaving and kill it. In order to signal iOS that your `on('notification')` handler is done you will need to call the new `push.finish()` method.
That covers what you need to do on the server side to accept background pushes on iOS. However, it is critically important that you continue reading as there will be a change in your `on('notification')`. When you receive a background push on iOS you will be given 30 seconds of time in which to complete a task. If you spend longer than 30 seconds on the task the OS may decide that your app is misbehaving and kill it. In order to signal iOS that your `on('notification')` handler is done you will need to call the new `push.finish()` method.

For example:

Expand All @@ -594,11 +616,11 @@ For example:
"clearBadge": true
}
});

push.on('registration', function(data) {
// send data.registrationId to push service
});


push.on('notification', function(data) {
// do something with the push data
Expand All @@ -623,11 +645,11 @@ For advanced templates and usage, the notification object is included in [`data.

### Setting Toast Capable Option for Windows

This plugin automatically sets the toast capable flag to be true for Cordova 5.1.1+. For lower versions, you must declare that it is Toast Capable in your app's manifest file.
This plugin automatically sets the toast capable flag to be true for Cordova 5.1.1+. For lower versions, you must declare that it is Toast Capable in your app's manifest file.

### Disabling the default processing of notifications by Windows

The default handling can be disabled by setting the 'cancel' property in the notification object.
The default handling can be disabled by setting the 'cancel' property in the notification object.

```
data.additionalData.pushNotificationReceivedEventArgs.cancel = true
Expand Down
9 changes: 5 additions & 4 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

<config-file target="AndroidManifest.xml" parent="/manifest/application">
<activity android:name="com.adobe.phonegap.push.PushHandlerActivity" android:exported="true"/>

<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
Expand All @@ -71,7 +71,7 @@
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID"/>
</intent-filter>
</service>
</service>
</config-file>

<framework src="com.android.support:support-v13:23+" />
Expand All @@ -82,6 +82,7 @@
<source-file src="src/android/com/adobe/phonegap/push/PushHandlerActivity.java" target-dir="src/com/adobe/phonegap/push/" />
<source-file src="src/android/com/adobe/phonegap/push/PushInstanceIDListenerService.java" target-dir="src/com/adobe/phonegap/push/" />
<source-file src="src/android/com/adobe/phonegap/push/PushPlugin.java" target-dir="src/com/adobe/phonegap/push/" />
<source-file src="src/android/com/adobe/phonegap/push/PermissionUtils.java" target-dir="src/com/adobe/phonegap/push/" />

</platform>

Expand All @@ -93,13 +94,13 @@
<param name="ios-package" value="PushPlugin"/>
</feature>
</config-file>

<config-file target="*-Info.plist" parent="UIBackgroundModes">
<array>
<string>remote-notification</string>
</array>
</config-file>

<source-file src="src/ios/AppDelegate+notification.m" />
<source-file src="src/ios/PushPlugin.m" />

Expand Down
56 changes: 56 additions & 0 deletions src/android/com/adobe/phonegap/push/PermissionUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.adobe.phonegap.push;

import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class PermissionUtils {

private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";

public static boolean hasPermission(Context appContext, String appOpsServiceId) throws UnknownError {

AppOpsManager mAppOps = (AppOpsManager) appContext.getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo appInfo = appContext.getApplicationInfo();

String pkg = appContext.getPackageName();
int uid = appInfo.uid;
Class appOpsClass = null;

try {

appOpsClass = Class.forName(AppOpsManager.class.getName());

Method checkOpNoThrowMethod = appOpsClass.getMethod(
CHECK_OP_NO_THROW,
Integer.TYPE,
Integer.TYPE,
String.class
);

Field opValue = appOpsClass.getDeclaredField(appOpsServiceId);

int value = (int) opValue.getInt(Integer.class);
Object result = checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg);

return Integer.parseInt(result.toString()) == AppOpsManager.MODE_ALLOWED; // type madness

} catch (ClassNotFoundException e) {
throw new UnknownError("class not found");
} catch (NoSuchMethodException e) {
throw new UnknownError("no such method");
} catch (NoSuchFieldException e) {
throw new UnknownError("no such field");
} catch (InvocationTargetException e) {
throw new UnknownError("invocation target");
} catch (IllegalAccessException e) {
throw new UnknownError("illegal access");
}

}

}
1 change: 1 addition & 0 deletions src/android/com/adobe/phonegap/push/PushConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public interface PushConstants {
public static final String UNREGISTER = "unregister";
public static final String EXIT = "exit";
public static final String FINISH = "finish";
public static final String HAS_PERMISSION = "hasPermission";
public static final String ANDROID = "android";
public static final String SENDER_ID = "senderID";
public static final String CLEAR_NOTIFICATIONS = "clearNotifications";
Expand Down
22 changes: 19 additions & 3 deletions src/android/com/adobe/phonegap/push/PushPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,22 @@ public void run() {
});
} else if (FINISH.equals(action)) {
callbackContext.success();
} else if (HAS_PERMISSION.equals(action)) {
cordova.getThreadPool().execute(new Runnable() {
public void run() {
JSONObject jo = new JSONObject();
try {
jo.put("isEnabled", PermissionUtils.hasPermission(getApplicationContext(), "OP_POST_NOTIFICATION"));
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, jo);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
} catch (UnknownError e) {
callbackContext.error(e.getMessage());
} catch (JSONException e) {
callbackContext.error(e.getMessage());
}
}
});
} else {
Log.e(LOG_TAG, "Invalid action : " + action);
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
Expand Down Expand Up @@ -240,7 +256,7 @@ private static JSONObject convertBundleToJson(Bundle extras) {
while (it.hasNext()) {
String key = it.next();
Object value = extras.get(key);

Log.d(LOG_TAG, "key = " + key);

if (jsonKeySet.contains(key)) {
Expand All @@ -265,7 +281,7 @@ else if (strValue.startsWith("[")) {
}
else {
additionalData.put(key, value);
}
}
} catch (Exception e) {
additionalData.put(key, value);
}
Expand All @@ -290,4 +306,4 @@ public static boolean isInForeground() {
public static boolean isActive() {
return gWebView != null;
}
}
}
26 changes: 19 additions & 7 deletions src/ios/AppDelegate+notification.m
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N
pushHandler.notificationMessage = userInfo;
pushHandler.isInline = YES;
[pushHandler notificationReceived];

completionHandler(UIBackgroundFetchResultNewData);
}
// app is in background or in stand by
else {
NSLog(@"app in-active");

// do some convoluted logic to find out if this should be a silent push.
long silent = 0;
id aps = [userInfo objectForKey:@"aps"];
Expand All @@ -88,18 +88,18 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N
} else if ([contentAvailable isKindOfClass:[NSNumber class]]) {
silent = [contentAvailable integerValue];
}

if (silent == 1) {
NSLog(@"this should be a silent push");
void (^safeHandler)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult result){
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(result);
});
};

NSMutableDictionary* params = [NSMutableDictionary dictionaryWithCapacity:2];
[params setObject:safeHandler forKey:@"handler"];

PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
pushHandler.notificationMessage = userInfo;
pushHandler.isInline = NO;
Expand All @@ -109,12 +109,24 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N
NSLog(@"just put it in the shade");
//save it for later
self.launchNotification = userInfo;

completionHandler(UIBackgroundFetchResultNewData);
}
}
}

- (BOOL)userHasRemoteNotificationsEnabled {
UIApplication *application = [UIApplication sharedApplication];
if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
return application.currentUserNotificationSettings.types != UIUserNotificationTypeNone;
} else {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return application.enabledRemoteNotificationTypes != UIRemoteNotificationTypeNone;
#pragma GCC diagnostic pop
}
}

- (void)applicationDidBecomeActive:(UIApplication *)application {

NSLog(@"active");
Expand All @@ -123,7 +135,7 @@ - (void)applicationDidBecomeActive:(UIApplication *)application {
if (pushHandler.clearBadge) {
NSLog(@"PushPlugin clearing badge");
//zero badge
application.applicationIconBadgeNumber = 0;
application.applicationIconBadgeNumber = 0;
} else {
NSLog(@"PushPlugin skip clear badge");
}
Expand Down
Loading