How to give permission to files in android using cordova - android

I have created a vue project where I am using cordova as plugin in vue. I have a scenario where using cordova file-transfer plugin I want to upload the file on to the server I have created in node.js using multer package.
I can able to select the files but the files aren't getting upload because of some permission denial.
So how can I resolve my problem I have added the permissions in AndroidManifest.xml file but still its denying my permission I don't what the hell is wrong with this application.
Any help would be appreciated...
CLIENT SIDE CODE
<template>
<div><br>
<hr><br><br>
<v-btn color="warning" #click="selectFiles()">Upload Files</v-btn>
</div>
</template>
<script>
export default {
data() {
return {
}
},
mounted() {
document.addEventListener("deviceready", onDeviceReady , false);
function onDeviceReady() {
console.log(window.FileTransfer);
}
},
methods: {
selectFiles() {
window.fileChooser.open((file) => {
this.upload(file.uri + file.name)
})
},
upload(fileURL){
var permissions = window.cordova.plugins.permissions;
permissions.hasPermission(permissions.CAMERA, function( status ){
if ( status.hasPermission ) {
alert("Yes :D ");
}
else {
alert("No :( ");
permissions.requestPermissions(
[permissions.ACTION_OPEN_DOCUMENT],
function(status) {
if( !status.hasPermission ) alert("hhh");
},
alert('Camera or Accounts permission is not turned on'));
}
});
var path = fileURL
path = path.replace("%", "%25");
alert('path: '+path)
fileURL = path
var options = new window.FileUploadOptions();
options.fileKey = "image";
options.httpMethod = 'POST';
options.fileName = fileURL.substr(fileURL.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
var ft = new window.FileTransfer();
ft.upload(fileURL, encodeURI("http://localhost:8000/user/fileUpload"), (r)=>
{
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);}, (error)=>{
alert(JSON.stringify(error));
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}, options);
}
}
}
</script>
SERVER SIDE CODE
var express = require('express');
const app = express();
const port = 8000;
app.get('/', (req, res) => {
res.send('hello people');
});
var multer = require('multer');
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, '/upload');
},
filename: function (req, file, cb) {
cb(null , file.originalname);
}
});
var upload = multer({dest:'uploads/'});
// var upload = multer({ storage: storage })
app.post('/user/fileUpload', upload.single('image'), (req, res) => {
try {
res.send(req.file);
}catch(err) {
res.send(400);
}
});
app.listen(port, () => {
console.log('listening to the port: ' + port);
});
AndroidManifest.xml
<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="10000" android:versionName="1.0.0" package="com.vue.example.app" xmlns:android="http://schemas.android.com/apk/res/android">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<application android:hardwareAccelerated="true" android:icon="#mipmap/ic_launcher" android:label="#string/app_name" android:supportsRtl="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:label="#string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:theme="#android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="#string/launcher_name">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/camera_provider_paths" />
</provider>
</application>
</manifest>
When I am selecting the image file from the folder its giving me the alert message of Camera or Accounts permission is not turned on and then its giving the alert message of something like this:-
{"code";3,"source"."content://com.android.providers.media.documents/document/image%253A1961Image-name.jpg","target":my server api. "Permission Denial":reading com.android.providers.media.documents/MediaDocumentsProvideruri requires that you obtain access using ACTION_OPEN_DOCUMENT or related API's.

I solved it the only thing I was doing wrong is that I was passing the name of file with its uri, we only need to pass the uri in fileChooser.open() function. I will post the client side code. Here is the solution :-
SOLVED CLIENT CODE
<template>
<div><br>
<hr><br><br>
<v-btn color="warning" #click="selectFiles()">Upload Files</v-btn>
</div>
</template>
<script>
export default {
data() {
return {
}
},
mounted() {
document.addEventListener("deviceready", onDeviceReady , false);
function onDeviceReady() {
console.log(window.FileTransfer);
}
},
methods: {
selectFiles() {
window.fileChooser.open((file) => {
this.upload(file.uri);
})
},
upload(fileURL) {
var options = new window.FileUploadOptions();
options.fileKey = "image";
options.httpMethod = 'POST';
options.fileName = fileURL.substr(fileURL.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
var ft = new window.FileTransfer();
ft.upload(fileURL, encodeURI("http://192.168.1.111:8000/user/fileUpload"), (r)=>
{
alert("uploaded successfully..")
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);}, (error)=>{
alert(JSON.stringify(error));
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}, options);
}
}
}
</script>

Related

React native image picker camera crashes

I am using image picker in react native but an error occurs:
file:///storage/emulated exposed beyond app through clipdata.item
On ios, the camera opens normally. and in android i can pick an image from gallery normally.
My code:
const selectFile = (itemI,inputValue) => {
let options = {
title: 'Select Image',
maxWidth:800,
maxHeight:800,
quality:0.2,
storageOptions: {
skipBackup: true,
path: 'images',
},
includeBase64: true,
saveToPhotos:true
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log(
'User tapped custom button: ',
response.customButton
);
alert(response.customButton);
} else {
//let source = response;
// You can also display the image using data:
let source = {
uri: 'data:image/jpeg;base64,' + response.data
};
filePath[itemI]=source;
addItemCustom(" ");
}
});
};
I tried to add:
<uses-feature android:name="android.hardware.camera.any" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
....
android:requestLegacyExternalStorage="true"
...>
but the error is the same.

How to implement Android Background service in a NativeScript Angular project?

I'm trying to create a background service for nativescript-geolocation to get notifications when an event has been triggered.
I've found a lot of examples for the general NS version, but nothing for the Angular version and I can't find the way to implement it.
Currently, I'm getting Class "com.nativescript.location.BackgroundService" not found. error messages.
Services have been declared in the AndroidManifest.xml, deleted the platforms dir, and did a clean build.
<service android:name="com.nativescript.location.BackgroundService"
android:exported="false" >
</service>
<service android:name="com.nativescript.location.BackgroundService26"
android:permission="android.permission.BIND_JOB_SERVICE"
android:enabled="true"
android:exported="false">
</service>
I use this as a reference and trying to create the Angular version of this
https://github.com/NativeScript/nativescript-geolocation/tree/master/demo
background-service.ts
import * as geolocation from "nativescript-geolocation";
import { Accuracy } from "tns-core-modules/ui/enums";
import * as application from "tns-core-modules/application";
import { device } from "tns-core-modules/platform";
import * as Toast from "nativescript-toast";
let watchId;
function _clearWatch() {
if (watchId) {
geolocation.clearWatch(watchId);
watchId = null;
}
}
function _startWatch() {
geolocation.enableLocationRequest().then(function () {
_clearWatch();
watchId = geolocation.watchLocation(
function (loc) {
if (loc) {
let toast = Toast.makeText('Background Location: \n' + loc.latitude + ', ' + loc.longitude);
toast.show();
console.log('Background Location: ' + loc.latitude + ' ' + loc.longitude);
}
},
function (e) {
console.log("Background watchLocation error: " + (e.message || e));
},
{
desiredAccuracy: Accuracy.high,
updateDistance: 1.0,
updateTime: 3000,
minimumUpdateTime: 100
});
}, function (e) {
console.log("Background enableLocationRequest error: " + (e.message || e));
});
}
application.on(application.exitEvent, _clearWatch);
export function getBackgroundServiceClass() {
if (application.android) {
if (device.sdkVersion < "26") {
#JavaProxy("com.nativescript.location.BackgroundService")
class BackgroundService extends (<any>android).app.Service {
constructor() {
super();
return global.__native(this);
}
onStartCommand(intent, flags, startId) {
console.log('service onStartCommand');
this.super.onStartCommand(intent, flags, startId);
return android.app.Service.START_STICKY;
}
onCreate() {
console.log('service onCreate');
_startWatch();
}
onBind(intent) {
console.log('service onBind');
}
onUnbind(intent) {
console.log('service onUnbind');
}
onDestroy() {
console.log('service onDestroy');
_clearWatch();
}
}
return BackgroundService;
} else {
#JavaProxy("com.nativescript.location.BackgroundService26")
class BackgroundService26 extends (<any>android.app).job.JobService {
constructor() {
super();
return global.__native(this);
}
onStartJob(): boolean {
console.log('service onStartJob');
_startWatch();
return true;
}
onStopJob(jobParameters: any): boolean {
console.log('service onStopJob');
this.jobFinished(jobParameters, false);
_clearWatch();
return false;
}
}
return BackgroundService26;
}
} else {
return null;
}
}
export const BackgroundServiceClass = getBackgroundServiceClass();
app.component.tns.ts
import {Component, ElementRef, ViewChild} from '#angular/core';
import { BackgroundServiceClass } from "#src/background-service";
import { Page } from "tns-core-modules/ui/page";
const utils = require("tns-core-modules/utils/utils");
import * as application from "tns-core-modules/application";
import { device } from "tns-core-modules/platform";
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
/* Background servie stuffs */
page: Page;
watchIds = [];
jobId = 308; // the id should be unique for each background job. We only use one, so we set the id to be the same each time.
com: any;
constructor(
) {
}
ngOnInit(){
application.on(application.exitEvent, this._stopBackgroundJob);
}
ngAfterViewInit(){
}
_stopBackgroundJob() {
if (application.android) {
let context = utils.ad.getApplicationContext();
const jobScheduler = context.getSystemService((<any>android.content.Context).JOB_SCHEDULER_SERVICE);
if (jobScheduler.getPendingJob(this.jobId) !== null) {
jobScheduler.cancel(this.jobId);
console.log(`Job Canceled: ${this.jobId}`);
}
}
}
startBackgroundTap() {
if (application.android) {
let context = utils.ad.getApplicationContext();
if (device.sdkVersion >= "26") {
const jobScheduler = context.getSystemService((<any>android.content.Context).JOB_SCHEDULER_SERVICE);
const component = new android.content.ComponentName(context, BackgroundServiceClass.class);
const builder = new (<any>android.app).job.JobInfo.Builder(this.jobId, component);
builder.setOverrideDeadline(0);
jobScheduler.schedule(builder.build());
} else {
let intent = new android.content.Intent(context, BackgroundServiceClass.class);
context.startService(intent);
}
}
}
}
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android" package="__PACKAGE__" android:versionCode="13" android:versionName="1.31">
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="#drawable/icon" android:label="#string/app_name" android:theme="#style/AppTheme" android:windowSoftInputMode="adjustResize" android:hardwareAccelerated="true" android:networkSecurityConfig="#xml/network_security_config">
<service android:name="com.nativescript.location.BackgroundService"
android:exported="false" >
</service>
<service android:name="com.nativescript.location.BackgroundService26"
android:permission="android.permission.BIND_JOB_SERVICE"
android:enabled="true"
android:exported="false">
</service>
<activity android:name="com.tns.NativeScriptActivity" android:label="#string/title_activity_kimera" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode" android:theme="#style/LaunchScreenTheme">
<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="#style/AppTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.tns.ErrorReportActivity" />
</application>
</manifest>
For the problem you mention try this:
Check your version of Nativescript and the version the example. Breaking changes between versions may be affecting. Try a downgrade to Nativescript 5, create a new project and paste your code.
Then, try a clean build.
For Background Location Tracking, I suggest you to try Foreground Services combined with nativescript-geolocation plugin. Check this article is a well explained tutorial of the first topic:
https://dev.to/ozymandiasthegreat/android-continuous-background-services-with-nativescript-42c9
Repo link:
https://github.com/OzymandiasTheGreat/Nativescript-ServiceExample/blob/master/package-lock.json

how can I add attribute to the android activity from plugin.xml in cordova?

I have my activity in AndroidManifest.xml :
<activity android:name="mobile_app" >
</activity>
I want to add an attribute to the activity to be like this:
<activity android:name="mobile_app" android:launchMode="singleInstance" >
</activity>
I know that I can add the attribute directly in the androidManifest.xml an it works but I want my plugin to add the attribute to the activity tag.
Any help please ?
I too need to do this, but it looks like it's not possible:
The config-file element only allows you to append new children to an XML document tree.
https://cordova.apache.org/docs/en/5.0.0/plugin_ref_spec.md.html
It looks like hooks are the way to do it.
I did this in a way similar to that suggested in https://stackoverflow.com/a/32394342/2569560
In config.xml, inside <platform name="android"> , add
<hook type="after_build" src="scripts/androidMainActivityAttributeAdd.js" />
Then, add a script called androidMainActivityAttributeAdd.js. Here you
append the attribute inside the activity tag .
#!/usr/bin/env node
module.exports = function(context) {
var fs = context.requireCordovaModule('fs'),
path = context.requireCordovaModule('path');
var platformRoot = path.join(context.opts.projectRoot, 'platforms/android');
var manifestFile = path.join(platformRoot, 'AndroidManifest.xml');
if (fs.existsSync(manifestFile)) {
fs.readFile(manifestFile, 'utf8', function (err,data) {
if (err) {
throw new Error('Unable to find AndroidManifest.xml: ' + err);
}
var attribute = 'android:launchMode="singleInstance"';
if (data.indexOf(attribute) == -1) {
var result = data.replace(/android:name="MainActivity"/g, 'android:name="MainActivity" ' + attribute);
fs.writeFile(manifestFile, result, 'utf8', function (err) {
if (err) throw new Error('Unable to write into AndroidManifest.xml: ' + err);
})
}
});
}
};
Add this to your plugin.xml for your android platform element:
<platform name="android">
<config-file target="AndroidManifest.xml" parent="/manifest/application">
<activity android:name="mobile_app" android:launchMode="singleInstance" />
</config-file>
</platform>

Permissions to include in Android Manifest for GCM Push Notifications

Im trying to develop a cross platform application which will receive push notifications from Amazon SNS. The push notifications are working just fine for iOS, but for Android, im kind of at cross roads currently.
The push notifications are viewable when the Android App is focussed. However, no matter what variables related to ti.cloudpush i set(listed below).
The issue is - i am not able to get the push notifications to be shown in the notification tray.
CloudPush.showAppOnTrayClick = true;
CloudPush.showTrayNotification = true;
CloudPush.showTrayNotificationsWhenFocused= false;
CloudPush.singleCallback = true;
I guess this is related to Permissions that i might have to set iin the tiapp.xml for the Android Manifest section. I have included the list of permissions currently used below -
<android xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk>14</uses-sdk>>
<manifest>
<uses-sdk android:minSdkVersion="14"/>
<permission android:name="com.test.push.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
<uses-permission android:name="com.test.push.permission.C2D_MESSAGE"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application>
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<!-- Start receiver on boot -->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT"/>
<category android:name="android.intent.category.HOME"/>
</intent-filter>
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="com.test.push"/>
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="com.test.push.permission"/>
</intent-filter>
</receiver>
</application>
</manifest>
</android>
Could someone please let me know what i am doing wrong/ How to get this right ?
Any information/permissions related link would be highly appreciated.
Try this code :
app.js class :
/*
Push notifications through device token.
Steps :
1) Retrieve device token
2) Subscribe for receiving notifications
3) Notify
4) Unsubscribe from receiving notifications
*/
Titanium.UI.setBackgroundColor('#000');
var GcmWin = Ti.UI.createWindow({
backgroundColor : '#ccc',
title : 'Android Cloud Push Notification'
});
var CloudPush = require('ti.cloudpush');
CloudPush.debug = true;
CloudPush.enabled = true;
CloudPush.showTrayNotificationsWhenFocused = true;
CloudPush.focusAppOnPush = false;
var deviceToken;
var Cloud = require('ti.cloud');
Cloud.debug = true;
var submit = Ti.UI.createButton({
title : 'Retrieve Device token',
color : '#000',
height : 80,
width : 200,
top : 50
});
var subscribe = Ti.UI.createButton({
title : 'Subscribe',
color : '#000',
height : 80,
width : 200,
top : 150
});
subscribe.addEventListener('click', subscribeToChannel);
GcmWin.add(subscribe);
var notify = Ti.UI.createButton({
title : 'Notify',
color : '#000',
height : 80,
width : 200,
top : 250
});
notify.addEventListener('click', sendTestNotification);
GcmWin.add(notify);
var unsubscribe = Ti.UI.createButton({
title : 'Unsubscribe',
color : '#000',
height : 80,
width : 200,
top : 350
});
unsubscribe.addEventListener('click', unsubscribeToChannel);
GcmWin.add(unsubscribe);
GcmWin.add(submit);
submit.addEventListener('click', function(e) {
CloudPush.retrieveDeviceToken({
success : function deviceTokenSuccess(e) {
alert('Device Token: ' + e.deviceToken);
deviceToken = e.deviceToken;
},
error : function deviceTokenError(e) {
alert('Failed to register for push! ' + e.error);
}
});
});
function subscribeToChannel() {
// Subscribes the device to the 'test' channel
// Specify the push type as either 'android' for Android or 'ios' for iOS
Cloud.PushNotifications.subscribeToken({
device_token : deviceToken,
channel : 'test',
type : Ti.Platform.name == 'android' ? 'android' : 'ios'
}, function(e) {
if (e.success) {
alert('Subscribed');
} else {
alert('Error:\n' + ((e.error && e.message) || JSON.stringify(e)));
}
});
}
function sendTestNotification() {
// Sends an 'This is a test.' alert to specified device if its subscribed to the 'test' channel.
Cloud.PushNotifications.notifyTokens({
to_tokens : deviceToken,
channel : 'test',
payload : 'This is a test.'
}, function(e) {
if (e.success) {
alert('Push notification sent');
} else {
alert('Error:\n' + ((e.error && e.message) || JSON.stringify(e)));
}
});
}
function unsubscribeToChannel() {
// Unsubscribes the device from the 'test' channel
Cloud.PushNotifications.unsubscribeToken({
device_token : deviceToken,
channel : 'test',
}, function(e) {
if (e.success) {
alert('Unsubscribed');
} else {
alert('Error:\n' + ((e.error && e.message) || JSON.stringify(e)));
}
});
}
CloudPush.addEventListener('callback', function(evt) {
//alert(evt);
alert(evt.payload);
});
CloudPush.addEventListener('trayClickLaunchedApp', function(evt) {
Ti.API.info('Tray Click Launched App (app was not running)');
//alert('Tray Click Launched App (app was not running');
});
CloudPush.addEventListener('trayClickFocusedApp', function(evt) {
Ti.API.info('Tray Click Focused App (app was already running)');
//alert('Tray Click Focused App (app was already running)');
});
In tiapp.xml just check this below lines.Add it, if not there :
<modules>
<module platform="commonjs">ti.cloud</module>
<module platform="android">ti.cloudpush</module>
</modules>
This works for me. Hope this helps.

Pushwoosh and Android Phonegap App not communicating

The Problem
Okay so I have a Phonegap (2.3.0) android application with Pushwoosh to manage the push notifications. I followed the instructions, and got an app with only a few wording errors working. The app itself seems to run perfectly fine, however it doesn't seem like Pushwoosh is pushing anything to GCM (Google Cloud Messanger), which it turn isn't pushing anything to the app. Now that is what I think is wrong, however this is my first time using GCM and Pushwoosh.
On the Pushwoosh console page it shows each "push" as completed with no errors, but then on my GCM console it doesn't show any requests, nor do any notification pop up on my phone.
I have the GCM API key (server key) in my XML and my Pushwoosh is the correct XXXXX-XXXXX key. Here is my code to better outline how my code is setup (and maybe someone can see what I'm missing).
The Code
Here is the AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:resizeable="true"
android:anyDensity="true"
/>
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--library-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!--
Creates a custom permission so only this app can receive its messages.
NOTE: the permission *must* be called PACKAGE.permission.C2D_MESSAGE,
where PACKAGE is the application's package name.
-->
<permission
android:name="com.springmobile.employee.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>
<uses-permission
android:name="com.springmobile.employee.permission.C2D_MESSAGE"/>
<!-- This app has permission to register and receive data message. -->
<uses-permission
android:name="com.google.android.c2dm.permission.RECEIVE"/>
<application android:icon="#drawable/ic_launcher" android:label="#string/app_name" android:allowBackup="true">
<!--
Service for sending location updates
-->
<service android:name="com.arellomobile.android.push.GeoLocationService"/>
<intent-filter>
<action android:name="com.springmobile.employee.MESSAGE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<activity android:name="com.arellomobile.android.push.PushWebview"/>
<activity android:name="com.arellomobile.android.push.MessageActivity"/>
<activity android:name="com.arellomobile.android.push.PushHandlerActivity"/>
<!--
BroadcastReceiver that will receive intents from GCM
services and handle them to the custom IntentService.
The com.google.android.c2dm.permission.SEND permission is necessary
so only GCM services can send data messages for the app.
-->
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="com.springmobile.employee"/>
</intent-filter>
</receiver>
<!--
Application-specific subclass of PushGCMIntentService that will
handle received messages.
-->
<service android:name="com.arellomobile.android.push.PushGCMIntentService"/>
<activity android:name="org.apache.cordova.example.cordovaExample" android:label="#string/app_name"
android:theme="#android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Here is my Phonegap plugin config.XML
<plugins>
<plugin name="PushNotification" value="com.pushwoosh.plugin.pushnotifications.PushNotifications" onload="true"/>
</plugins>
Here is the JS for my Phonegap page to initialize and listen for the Pushwoosh Notification.
function initPushwoosh()
{
var pushNotification = window.plugins.pushNotification;
pushNotification.onDeviceReady();
pushNotification.registerDevice({ projectid: "I_HAVE_MY_PROJECT_ID_HERE", appid : "THIS_IS_MY_PUSHWOOSH_ID" },
function(status) {
var pushToken = status;
console.warn('push token: ' + pushToken);
},
function(status) {
console.warn(JSON.stringify(['failed to register ', status]));
}
);
document.addEventListener('push-notification', function(event) {
var title = event.notification.title;
var userData = event.notification.userdata;
if(typeof(userData) != "undefined") {
console.warn('user data: ' + JSON.stringify(userData));
}
navigator.notification.alert(title);
});
}
function init() {
document.addEventListener("deviceready", initPushwoosh, true);
//rest of the code
document.addEventListener('push-notification', function(event) {
var title = event.notification.title;
var userData = event.notification.userdata;
console.warn('user data: ' + JSON.stringify(userData));
navigator.notification.alert(title);
});
}
function initPushwoosh()
{
var pushNotification = window.plugins.pushNotification;
pushNotification.onDeviceReady();
document.addEventListener('push-notification', function(event) {
var title = event.notification.title;
var userData = event.notification.userdata;
if(typeof(userData) != "undefined") {
console.warn('user data: ' + JSON.stringify(userData));
}
navigator.notification.alert(title);
pushNotification.stopGeoPushes();
});
}
function registerPushwoosh()
{
var pushNotification = window.plugins.pushNotification;
//projectid: "GOOGLE_PROJECT_ID", appid : "PUSHWOOSH_APP_ID"
pushNotification.registerDevice({ projectid: "1039894503284", appid : "EE861-B95A3" },
function(token) {
alert(token);
onPushwooshInitialized(token);
},
function(status) {
alert("failed to register: " + status);
console.warn(JSON.stringify(['failed to register ', status]));
});
}
function unregisterPushwoosh()
{
var pushNotification = window.plugins.pushNotification;
pushNotification.unregisterDevice(function(token) {
alert("unregistered, old token " + token);
},
function(status) {
alert("failed to unregister: " + status);
console.warn(JSON.stringify(['failed to unregister ', status]));
});
}
//set the settings for Pushwoosh or set tags, this must be called only after successful registration
function onPushwooshInitialized(pushToken)
{
//output the token to the console
console.warn('push token: ' + pushToken);
var pushNotification = window.plugins.pushNotification;
//set multi notificaiton mode
//pushNotification.setMultiNotificationMode();
//set single notification mode
//pushNotification.setSingleNotificationMode();
//disable sound and vibration
//pushNotification.setSoundType(1);
//pushNotification.setVibrateType(1);
pushNotification.setLightScreenOnNotification(false);
//goal with count
//pushNotification.sendGoalAchieved({goal:'purchase', count:3});
//goal with no count
//pushNotification.sendGoalAchieved({goal:'registration'});
//setting list tags
//pushNotification.setTags({"MyTag":["hello", "world"]});
//settings tags
pushNotification.setTags({deviceName:"hello", deviceId:10},
function(status) {
console.warn('setTags success');
},
function(status) {
console.warn('setTags failed');
});
function geolocationSuccess(position) {
pushNotification.sendLocation({lat:position.coords.latitude, lon:position.coords.longitude},
function(status) {
console.warn('sendLocation success');
},
function(status) {
console.warn('sendLocation failed');
});
};
// onError Callback receives a PositionError object
//
function geolocationError(error) {
alert('code: ' + error.code + '\n' +
'message: ' + error.message + '\n');
}
function getCurrentPosition() {
navigator.geolocation.getCurrentPosition(geolocationSuccess, geolocationError);
}
//greedy method to get user position every 3 second. works well for demo.
// setInterval(getCurrentPosition, 3000);
//this method just gives the position once
// navigator.geolocation.getCurrentPosition(geolocationSuccess, geolocationError);
//this method should track the user position as per Phonegap docs.
// navigator.geolocation.watchPosition(geolocationSuccess, geolocationError, { maximumAge: 3000, enableHighAccuracy: true });
//Pushwoosh Android specific method that cares for the battery
pushNotification.startGeoPushes();
}
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicity call 'app.receivedEvent(...);'
onDeviceReady: function() {
initPushwoosh();
app.receivedEvent('deviceready');
//optional: create local notification alert
//var pushNotification = window.plugins.pushNotification;
//pushNotification.clearLocalNotification();
//pushNotification.createLocalNotification({"msg":"message", "seconds":30, "userData":"optional"});
},
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}
};
Here is the PushWoosh.js code
(function(cordova) {
function PushNotification() {}
// Call this to register for push notifications and retreive a deviceToken
PushNotification.prototype.registerDevice = function(config, success, fail) {
cordova.exec(success, fail, "PushNotification", "registerDevice", config ? [config] : []);
};
// Call this to set tags for the device
PushNotification.prototype.setTags = function(config, success, fail) {
cordova.exec(success, fail, "PushNotification", "setTags", config ? [config] : []);
};
// Call this to send geo location for the device
PushNotification.prototype.sendLocation = function(config, success, fail) {
cordova.exec(success, fail, "PushNotification", "sendLocation", config ? [config] : []);
};
//Android Only----
PushNotification.prototype.unregisterDevice = function(success, fail) {
cordova.exec(success, fail, "PushNotification", "unregisterDevice", []);
};
//config params: {msg:"message", seconds:30, userData:"optional"}
PushNotification.prototype.createLocalNotification = function(config, success, fail) {
cordova.exec(success, fail, "PushNotification", "createLocalNotification", config ? [config] : []);
};
PushNotification.prototype.clearLocalNotification = function() {
cordova.exec(null, null, "PushNotification", "clearLocalNotification", []);
};
//advanced background task to track device position and not drain the battery
PushNotification.prototype.startGeoPushes = function(success, fail) {
cordova.exec(success, fail, "PushNotification", "startGeoPushes", []);
};
PushNotification.prototype.stopGeoPushes = function(success, fail) {
cordova.exec(success, fail, "PushNotification", "stopGeoPushes", []);
};
//sets multi notification mode on
PushNotification.prototype.setMultiNotificationMode = function(success, fail) {
cordova.exec(success, fail, "PushNotification", "setMultiNotificationMode", []);
};
//sets single notification mode
PushNotification.prototype.setSingleNotificationMode = function(success, fail) {
cordova.exec(success, fail, "PushNotification", "setSingleNotificationMode", []);
};
//type: 0 default, 1 no sound, 2 always
PushNotification.prototype.setSoundType = function(type, success, fail) {
cordova.exec(success, fail, "PushNotification", "setSoundType", [type]);
};
//type: 0 default, 1 no vibration, 2 always
PushNotification.prototype.setVibrateType = function(type, success, fail) {
cordova.exec(success, fail, "PushNotification", "setVibrateType", [type]);
};
PushNotification.prototype.setLightScreenOnNotification = function(on, success, fail) {
cordova.exec(success, fail, "PushNotification", "setLightScreenOnNotification", [on]);
};
//set to enable led blinking when notification arrives and display is off
PushNotification.prototype.setEnableLED = function(on, success, fail) {
cordova.exec(success, fail, "PushNotification", "setEnableLED", [on]);
};
//{goal:'name', count:3} (count is optional)
PushNotification.prototype.sendGoalAchieved = function(config, success, fail) {
cordova.exec(success, fail, "PushNotification", "sendGoalAchieved", config ? [config] : []);
};
//Android End----
//iOS only----
PushNotification.prototype.onDeviceReady = function() {
cordova.exec(null, null, "PushNotification", "onDeviceReady", []);
};
// Call this to get a detailed status of remoteNotifications
PushNotification.prototype.getRemoteNotificationStatus = function(callback) {
cordova.exec(callback, callback, "PushNotification", "getRemoteNotificationStatus", []);
};
// Call this to set the application icon badge
PushNotification.prototype.setApplicationIconBadgeNumber = function(badge, callback) {
cordova.exec(callback, callback, "PushNotification", "setApplicationIconBadgeNumber", [{badge: badge}]);
};
// Call this to clear all notifications from the notification center
PushNotification.prototype.cancelAllLocalNotifications = function(callback) {
cordova.exec(callback, callback, "PushNotification", "cancelAllLocalNotifications", []);
};
//iOS End----
// Event spawned when a notification is received while the application is active
PushNotification.prototype.notificationCallback = function(notification) {
var ev = document.createEvent('HTMLEvents');
ev.notification = notification;
ev.initEvent('push-notification', true, true, arguments);
document.dispatchEvent(ev);
};
cordova.addConstructor(function() {
if(!window.plugins) window.plugins = {};
window.plugins.pushNotification = new PushNotification();
});
})(window.cordova || window.Cordova || window.PhoneGap);
Screenshots of GCM, Pushwoosh and Eclipse
Sorry this is lengthy but I want to make sure I have everything here. Also not enough rep to post images so links below.
GCM API server key, Pushwoosh Control Panel, and Eclipse setup
Thanks!
lets check your configuration and setup is proper for push woosh notification .Other Push notification service is also work in phone-gap you can check it out.You can find phone gap code(zip),proper documentation for configuration and setup and how to use their API using Java script
The Pushwoosh version is very important while configuring it with a phonegap application, so you need to be sure that your Pushwoosh script is compatible with Phonegap 2.3.0. If the Pushwoosh script is not correct, it will not work with your Phonegap version and I think that they only support the latest Phonegap available right now.
The GCM API key must be for Android Application, not server
I had this issue because my bundle id wasn't correct.
Be sure that your app name and the bundle id are the same in xcode and your iOS app Indentifier in https://developer.apple.com/account/ios/identifiers.

Categories

Resources