Call Swift function from Cordova - javascript

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.

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 :).

Electron - Invalid package on unzip

For around 3 weeks I've been working on an Electron app and finally decided to get around to adding update checking. For my research, the standard way to do this in Electron (using Squirrel) requires the user to physically install the application onto their computer. I would rather not do this, and keep everything as portable as possible. I then decided to try making my own update script by having the program download the update.zip, and extract it to overwrite the existing files. This works well, up until the very end. At the very end of the extraction, I receive a Invalid package error, and the actual app.asar file is missing, rendering the application useless.
I am using this to download and extract the updates:
function downloadFile(url, target, fileName, cb) { // Downloads
var req = request({
method: 'GET',
uri: url
});
var out = fs.createWriteStream(target+'/'+fileName);
req.pipe(out);
req.on('end', function() {
unzip(target+'/'+fileName, target, function() {
if (cb) {
cb();
}
});
});
}
function unzip(file, target, cb) { // Unzips
var out = fs.createReadStream(file);
out.pipe(unzipper.Extract({ path: target })).on('finish', function () {
dialog.showMessageBox({
type: 'question',
message: 'Finished extracting to `'+target+'`'
});
if (cb) {
cb();
}
});
}
And call it with:
downloadFile('http://example.com/update.zip', path.join(__dirname, './'), 'update.zip', function() { // http://example.com/update.zip is not the real source
app.relaunch();
app.quit();
});
And I use the unzipper NPM package (https://www.npmjs.com/package/unzipper).
The code works perfectly for all other zips, but it fails when trying to extract a zip containing an Electron app.
Anything I'm doing wrong, or maybe a different package that properly supports extracting zips with .asar files?
Edit 1
I just found https://www.npmjs.com/package/electron-basic-updater, which does not throw the same JavaScript error however it still does not extract the .asar files correctly, and will throw it's own error. Since the .asar is still missing, the app is still useless after the "update"
Thanks to your link to electron-basic-updater, I have found this issue mentioned there: https://github.com/TamkeenLMS/electron-basic-updater/issues/4.
They refer to the issue in the electron app: https://github.com/electron/electron/issues/9304.
Finally, in the end of the second topic there's a solution:
This is due to the electron fs module treating asar files as directories rather than files. To make the unzip process work you need to do one of two things:
Set process.noAsar = true
Use original-fs instead of fs
I have seen the people working with original-fs. But it looked like a big trouble to me.
So I tried setting process.noAsar = true (and then process.noAsar = false after unzipping) - and that worked like a charm.

How do I get intellisense for Javascript module in Atom or any other IDE?

I'm new to javascript and node js.
I've following code in my authentication.js file
I'm trying to get the intellisense working when I press client. ( and CTRL + space), I do not see anything.
How do I be able to see functions that are within auth.OAuth2 modules.
I remember in VS you can use /// reference paths. Not sure if that is the standard approach in ATOM as well. I looked over the internet and could not find any satisfactory answer.
How do people know what methods to use and what is their required signature without intellisense?
I'm literally crawling to make things work right now because of this. Do I have to read documentation for every modules/packages before I start using it? That'd take a lot of time.
Please also note that I have added all the packages like autocomplete, autocomplete-plus and so on for the intellisense to work magically but it doesn't. Intellisense does work but it displays everything else but not the functions of the modules I'm referring to in the example.
Any help/suggestion is much appreciated?
'use strict';
var config = require("../../config/config");
exports.verifyUser = function(req, res, next) {
var GoogleAuth = require('google-auth-library');
var auth = new GoogleAuth;
var client = new auth.OAuth2(config.clientID, config.clientSecret,config.callbackURL);
**client. //no intellisense**
// check header or url parameters or post parameters for token
var token = req.body.id_token || req.query.id_token || req.headers['id_token'];
if (token) {
client.verifyIdToken(
token,
config.clientID,
function (err) {
if (err) {
res.send("Un authorized");
} else {
next();
}
});
}
}
I've had great success using Visual Studio Code.
Its a lightweight IDE similar to Atom, its actually also built using Electron.
You can check out a tutorial about how to get things set up here.
https://blog.tallan.com/2017/03/02/synthetic-type-inference-in-javascript/
You need to add an intellesense plugin for the language you're using. Atom isn't really suited to noobs though, you should try out netbeans if you want a fully featured editor.

Authorization header using OAuth1.0A for Twitter API v1.1

I am building a search engine as a start-up project in Web Development. The search engine takes a string and queries the Wiki and Twitter API. I have been working on it for days and, I believe, I have found a nice, clean way to implement it.
BoyCook's TwitterJSClient
In his code (which is beautifully written) he has set up a Twitter function which takes in a config variable and sets up the authorization for us. Is there something it is missing? I have been through it and it all looks great. I am new to Javascript and might be missing something..
My code:
var error = function (err, response, body) {
console.log('ERROR [%s]', err);
};
var success = function (data) {
console.log('Data [%s]', data);
};
var config = {
"consumerKey": "{Mine}",
"consumerSecret": "{Mine}",
"accessToken": "{Mine}",
"accessTokenSecret": "{Mine}",
"callBackUrl": ""
}
var Twitter = require('twitter-node-client').Twitter;
var twitter = new Twitter(config);
twitter.getSearch({'q':'Lebron James','count': 10}, error, success);
Can anyone help? Have you done this before and know an easier way? Has anyone been able to get it working using postMessage()?
And yes... the origin is using HTTPS protocol. See: JBEngine. My app permission (on Twitter) is set to read only.
[EDIT] Should probably also mention that I glob'd it all together with browserify and am running the script client-side.

Pushwoosh phonegap plugin, retrieving hwid on ios

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);
}
}

Categories