Pushwoosh phonegap plugin, retrieving hwid on ios - javascript

I'm using pushwoosh to send push notifications to my ios mobile app. I want to allow users to disable notifications from within the app. The problem I'm having is that the pushwoosh api uses a different device id for ios than it does for android. The device id is created by the plugin using native code. It uses the hardware mac address and applies the md5 algorithm to create a "unique" id that phonegap is calling "hwid"(hardware id). I've found the native, objective c class that does this but I don't know how to access the variable, "hwid", from Javascript.
I've read through the phonegap documentation and have created a plugin that allows me to access native ios classes. My problem is that I don't know objective c and therefore cannot figure out how to return the variable to the callback.
The pushwoosh api requires the device id in order to unregister a device as you can see here:
{
"request":{
"application":"APPLICATION_CODE",
"hwid": "hardware device id"
}
}
I have seen this post and it is not helpful for what I'm trying to accomplish. However, it does show the native code that creates the unique id.
I also found this class that prints the hwid to the console. If I could find a way to access the "hwid" below from my js code I would be all set.
#import "PWRequest.h"
#implementation PWRequest
#synthesize appId, hwid;
- (NSString *) methodName {
return #"";
}
//Please note that all values will be processed as strings
- (NSDictionary *) requestDictionary {
return nil;
}
- (NSMutableDictionary *) baseDictionary {
NSMutableDictionary *dict = [NSMutableDictionary new];
[dict setObject:appId forKey:#"application"];
[dict setObject:hwid forKey:#"hwid"];
NSLog(#"hwid: %#", hwid);
return [dict autorelease];
}
- (void) parseResponse: (NSDictionary *) response {
}
- (void) dealloc {
self.appId = nil;
self.hwid = nil;
[super dealloc];
}
#end
Can someone point me in the right direction? Thanks.

We have just added unregisterDevice method for iOS Phonegap Javascript.
PushNotification.prototype.unregisterDevice = function(success, fail) {
cordova.exec(success, fail, "PushNotification", "unregisterDevice", []);
};
It used to work only for Android, now it is available on iOS as well.
For Phonegap 3.0 please see the newest Pushwoosh plugin repo:
https://github.com/shaders/pushwoosh-phonegap-3.0-plugin
For older Phonegap versions <= 2.9 please see legacy Pushwoosh Phonegap plugin:
https://github.com/shaders/phonegap-cordova-push-notifications/tree/master/iOS
I hope it helps!

I found a work-around for anyone who needs this. Just open up the class "PWRequest.m" in xcode. Add the code below just under "[dict setObject:hwid forKey:#"hwid"];" in the NSMutableDictionary method.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"hwidfile2.txt"];
NSLog(#"From Echo Class File Path: %#", filePath);
NSString *str = hwid;
This will save a text file to your local app directory in which you can access from your Javascript code. For example, you can use this JS code to access and print the hwid to the console. Just call the 'readPwfile(filename)' function, passing in the name of your file as the function argument.
function readPWFile(fileName){
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){
fileSystem.root.getFile(fileName, null, gotReadFileEntry, fail);
});
function gotReadFileEntry(fileEntry) {
fileEntry.file(gotFile, fail);
}
function gotFile(file){
//readDataUrl(file);
readAsText(file);
}
function readAsText(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log('Reading file... hwig Result: '+evt.target.result);
};
reader.readAsText(file);
}
}

Related

Call javascript method from Cordova Plugin's service

I am currently developing an App using Cordova and therefore have developed a Cordova Plugin, that runs a service and is being started from within that plugin:
public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
switch(action){
case "start":
Intent startIntent = new Intent(context, BackgroundService.class);
startIntent.putExtra("action", "play");
context.startService(startIntent);
return true;
}
return false;
}
The code is shortened for readability. Now normally I would use callbacks to call javascript methods from within the plugin, but as I want to use a service for the functionality, how could I call a method (or maybe the callback) from there?
Thank you very much in advance :).
Okay so I did not find a way to this with vanilla cordova, but this Plugin provides the functionality I was looking for: https://github.com/bsorrentino/cordova-broadcaster
You have to set up a LocalBroadcastManager in your native Android Code and send an Intent with it. You then define a bundle containg the data you want to send, and put it as extra of your intent. Then you send the intent via the broadcast manager and receive it via javascript.
Sample Java:
startCallback = new Intent("callback");
Bundle b = new Bundle();
b.putString("callback", "start");
startCallback.putExtras(b);
LocalBroadcastManager.getInstance(applicationContext).sendBroadcastSync(startCallback);
Sample Javascript:
var callbackListener = function( e ) {
console.log("What kind of callback: " + e.callback);
};
window.broadcaster.addEventListener( "callback", callbackListener);
I hope this helps somebody with a similiar problem :).

Call Swift function from Cordova

I have a native iOS app written in Swift and it works on standalone. However, currently, I am exploring Cordova and developing a plugin for it using the Swift codes that I already have. Let's say my native Swift code is the following and the function that I want to call is startDataLog():
func startDataLog() {
// Set file logging parameters and do some logging etc...
let fileName = "log_\(dateFormatter.string(from: Date())).log"
let filePath = URL(fileURLWithPath:
(NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask, true)[0] as
NSString).appendingPathComponent(fileName))
//do other stuffs here...
}
Assuming that the plugin.xml and the bridging header are correctly configured for the new plugin:
First, I need to add this in www/plugin.js that calls the iOS codes. In my case startDataLog:
var exec = require('cordova/exec');
var serviceName = 'DriverAppPlugin'
module.exports = {
'startDataLog': function (successCallback, errorCallback) {
cordova.exec(successCallback, errorCallback, serviceName,
'startDataLog', [])
},
}
Then in my native Swift code I will have to add the following:
#objc(CentralPlugin) class CentralPlugin: CDVPlugin {
func startDataLog(command: CDVInvokedUrlCommand) {
// Set file logging parameters and does some extras
let fileName = "log_\(dateFormatter.string(from: Date())).log"
let filePath = URL(fileURLWithPath:
(NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask, true)[0] as
NSString).appendingPathComponent(fileName))
//do other stuffs here...
}
}
What is unclear to me is if this is what needs to be done to the native Swift code or the function that I want to call? Is adding
(command: CDVInvokedUrlCommand)
to the func is correct or am I doing something terribly wrong here. I am new to Cordova and as a matter of fact, there are not many tutorials that are based on integrating Cordova + Swift.
Any feedback or directions will be really helpful to kickstart my plugin development. Please suggest.

Using Native UISearchBar to search a place on WKWebView

I'm still a beginner with Objective C
I developed a website using cakephp and I used a paid api for the map
Now I'm trying to build an iOS app but they don't have an iOS api so I only need to display the map into WKWebView
I removed all the buttons and created native buttons
I succeed to to inject JS to the native buttons using evaluateJavaScript and it works fine
But now I created an UISeachBar on the navigation bar and I'm using
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
I want to send the searchText to a JS function and then return an array
the problem is that when I created a JS function just for testing I get this message when I type String :
Error Domain=WKErrorDomain Code=4 "A JavaScript exception occurred" UserInfo={NSLocalizedDescription=A JavaScript exception occurred}
But when I type numbers it works fine
My Objc code :
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSString *function = [[NSString alloc] initWithFormat: #"getSuggest(%#)", searchText];
[_webView evaluateJavaScript:function completionHandler:^(NSString *result, NSError *error)
{
NSLog(#"Error %#",error);
NSLog(#"Result %#",result);
}];
}
My JS code :
var getSuggest = function(searchText) {
return searchText;
}
you have to embed the searchText into "" for the js function call:
NSString *function = [[NSString alloc] initWithFormat: #"getSuggest(\"%#\")", searchText];

Can i write a single plugin in phonegap-cordova which can be integrated in all native and hybrid application as third party tool?

I am new to mobile development.I have recent business requirement in
which i have to write in app plugin code for my client for their
already exiting application in ios and android. Client should be
easily able to integrate my pugin in their app.
The problem i facing now is client can have their app in native code
or it can be a phonegap ( hybrid ) app as well. So if i go full
native i have to write one for ios , one for android. On top of this
if client have hybride app i need to write one phonegap plugin as well
(i am not sure about this) ?
I went through https://www.helpshift.com/ and
https://www.uservoice.com/ and they seems to have three in app for ios
native , android native and for phonegap. Does there is obvious reason
for this ? would like to know ? To some my question
Can i write a single plugin in app in phonegap cordova which can be integrated in all native and hybrid application ? This would help me
as am working on javascript for a while and would be great to maintain
a single source code.
If no , what is the best practice ?
I'm not sure if understanding your question. Correct me if I'm wrong: you need a piece of code for Android and for iOS that could work as a cordova plugin as well?
In this case I think you could write your source code for each platform (as it should be written anyway for a cordova plugin), and then write a wrapper for cordova:
Android:
YourAwesomeClass.java
class YourAwesomeClass {
public void yourAwesomeMethod() {
}
}
CordovaPluginForYourAwesomeClass.java:
class CordovaPluginForYourAwesomeClass extends CordovaPlugin {
YourAwesomeClass yac;
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
yac = new YourAwesomeClass();
}
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
PluginResult result = null;
if ("yourJsHook".equals(action)) {
result = executeYourJsHook(args, callbackContext);
} elseĀ {
return false;
}
if (result != null) {
callbackContext.sendPluginResult(result);
}
return true;
}
private PluginResult executeYourJsHook(JSONArray args, CallbackContext callbackContext) {
yac.yourAwesomeMethod();
callbackContext.success();
return null;
}
}
iOS:
YourAwesomeClass.h:
#interface YourAwesomeClass {
}
-(void) yourAwesomeMethod;
YourAwesomeClass.m:
#implementation YourAwesomeClass
-(void) yourAwesomeMethod {
}
#end
CordovaPluginForYourAwesomeClass.h:
#interface CordovaPluginForYourAwesomeClass : CDVPlugin {
}
#property(nonatomic, retain) YourAwesomeClass *yac;
-(void) yourJsHook: (CDVInvokedUrlCommand *)command;
CordovaPluginForYourAwesomeClass.m:
#interface CordovaPluginForYourAwesomeClass
#synthesize yac;
-(CDVPlugin *)initWithWebView:(UIWebView *)theWebView {
self = (CDVAdMobAds *)[super initWithWebView:theWebView];
yac = [YourAwesomeClass init];
return self;
}
-(void) yourJsHook: (CDVInvokedUrlCommand *)command {
CDVPluginResult *pluginResult;
NSString *callbackId = command.callbackId;
NSArray* args = command.arguments;
[yac yourAwesomeMethod];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
[self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
}
#end
yourAwesomeJsBridge.js:
yourAwesomeJsBridge.yourJsHook = function(success, failure, options) {
cordova.exec(success, failure, "CordovaPluginForYourAwesomeClass", "yourJsHook", [ options ]);
}
For native code you could use YourAwesomeClass and for cordvoa apps you should use your plugin (see Cordova Documentation)
You can look at the source code for cordova plugin in the cordova plugin repository.

Pushwoosh phonegap plugin, retrieving device ID

I'm using the pushwoosh phonegap plugin for push notifications. After successful registration I need to store the device ID that the registration used in the "hwid" parameter so that I can target push notifications that I send with this same device ID. This works great on Android since it seems the phonegap device.uuid is the same ID that the pushwoosh plugin is sending to their servers. However, on ios the device.uuid returns a different ID than what is sent to pushwoosh. I can see from the Xcode console log the hwid that the plugin is sending to pushwoosh but cannot figure out where they are getting this ID from and how to access the same ID within phonegap.
EDIT: I was hoping the getRemoveNotificationStatus function would return this info but it actually returns less than the registerDevice callback.
UPDATE: Ok, from digging through their plugin code I see where they are constructing this ID that they send to their servers. Not sure why this ID isn't accessible through the phonegap plugin since this is the ID that I ultimately need to have in order to target a push notification to the specific device.
Their code:
(NSString *) uniqueDeviceIdentifier{
NSString *macaddress = [self macaddress];
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
NSString *stringToHash = [NSString stringWithFormat:#"%#%#",macaddress,bundleIdentifier];
NSString *uniqueIdentifier = [self stringFromMD5:stringToHash];
return uniqueIdentifier;
}
- (NSString *) uniqueGlobalDeviceIdentifier{
// >= iOS6 return identifierForVendor
UIDevice *device = [UIDevice currentDevice];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.1")) {
if ([device respondsToSelector:#selector(identifierForVendor)] && [NSUUID class]) {
NSUUID *uuid = [device identifierForVendor];
return [uuid UUIDString];
}
}
// Fallback on macaddress
NSString *macaddress = [self macaddress];
NSString *uniqueIdentifier = [self stringFromMD5:macaddress];
return uniqueIdentifier;
}
Are you sure that you need the hwid?
When I use the Pushwoosh Remote API to send push messages to individual devices I target using the "devices" tag and then just supply the deviceToken of the devices I wish to message.
The device token is easily accessible as it's part of the status-return from the plugin (status['deviceToken']).
As I posted here.
I found a work-around for anyone who needs this. Just open up the class "PWRequest.m" in xcode. Add the code below just under "[dict setObject:hwid forKey:#"hwid"];" in the NSMutableDictionary method.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"hwidfile2.txt"];
NSLog(#"From Echo Class File Path: %#", filePath);
NSString *str = hwid;
This will save a text file to your local app directory in which you can access from your Javascript code. For example, you can use this JS code to access and print the hwid to the console. Just call the 'readPwfile(filename)' function, passing in the name of your file as the function argument.
function readPWFile(fileName){
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){
fileSystem.root.getFile(fileName, null, gotReadFileEntry, fail);
});
function gotReadFileEntry(fileEntry) {
fileEntry.file(gotFile, fail);
}
function gotFile(file){
//readDataUrl(file);
readAsText(file);
}
function readAsText(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log('Reading file... hwig Result: '+evt.target.result);
};
reader.readAsText(file);
}
}

Categories