How to upgrade javascript to utilize phonegap 2.3 custom plugin? - java

I have built a custom plugin called TCPIPCommPlugin that uses Phonegap/Cordova 1.6.1. Everything is all great and the callbacks/plugin results work just fine. However I need to get it upgraded to Cordova 2.3. The reason is that we are now starting dev on Win8 as well as iOS/Android.
That aside, I have the following code in javascript.
var TCPComm = function() {
};
TCPComm.prototype.Open = function(Cmd,successCallback, failureCallback) {
return PhoneGap.exec( successCallback, //Success callback from the plugin
failureCallback, //Error callback from the plugin
'TCPIPCommPlugin', //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
'Open', //Tell plugin, which action we want to perform
[Cmd]); //Passing list of args to the plugin
};
This code continues with about 10-12 different function calls to the plugin, which is then concluded with...
PhoneGap.addConstructor(function() {
PhoneGap.addPlugin("TCPComm", new TCPComm());
});
Within the javascript itself, the actual function call looks like this.
window.plugins.TCPComm.Open(g_IpAddr, OpenOK,OpenFail);
Additionally here is what the JAVA Plugin looks like.
#Override
public PluginResult execute(String action, JSONArray data, String callbackId) {
PluginResult result = null;
try {
Actions currentAction = Actions.valueOf(action.toUpperCase());
JSONObject Resp = new JSONObject();
String RespStr;
switch(currentAction){
case OPEN:
{
//do work
}catch (JSONException jsonEx) {
System.out.println(jsonEx.toString());
result = new PluginResult(Status.JSON_EXCEPTION);
}
return result;}
This works great with Cordova 1.6.1. However not so much with Cordova 2.x.x. Now with all this said and done, I have perused the web trying to find a way to convert the JAVA. I came up with the following.
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
PluginResult result = null;
try {
Actions currentAction = Actions.valueOf(action.toUpperCase());
JSONObject Resp = new JSONObject();
String RespStr;
switch(currentAction){
case OPEN:
{
//do work
}catch (JSONException jsonEx) {
System.out.println(jsonEx.toString());
result = new PluginResult(Status.JSON_EXCEPTION);
}
return true;
}
This seems to match the updated code. What I have not been able to find is a way to update the JAVASCRIPT calls to make this plugin work with the updated CORDOVA.
Any help/points in the right direction would be much appreciated!
I have used the following documentation with no success.
http://docs.phonegap.com/en/2.3.0/guide_plugin-development_index.md.html#Plugin%20Development%20Guide
https://github.com/apache/cordova-android/tree/master/framework/src/org/apache/cordova
UPDATE
Thanks for the response Simon. In the interim I had replaced my javascript with the following. Do I need to revert it back to what it was prior?
cordova.define("cordova/plugin/TCPIPCommPlugin", function(require, exports, module){
var exec = require('cordova/exec');
var TCPComm = function() {};
// var TCPCommError = function(code, message) {
// this.code = code || null;
// this.message = message || '';
// };
TCPComm.prototype.Open = function(success,fail) {
return cordova.exec( successCallback, //Success callback from the plugin
failureCallback, //Error callback from the plugin
'TCPIPCommPlugin', //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
'Open', //Tell plugin, which action we want to perform
[Cmd]);
};
var TCPIPCommPlugin = new TCPComm();
module.exports = TCPIPCommPlugin;
});
UPDATE #2 - Fixed some errors
I went back to the old javascript and replaced it all so it looks like this now..
var TCPComm = function() {};
TCPComm.prototype.Open = function(Cmd, successCallback,failureCallback) {
return cordova.exec( successCallback, //Success callback from the plugin
failureCallback, //Error callback from the plugin
'TCPIPCommPlugin', //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
'Open', //Tell plugin, which action we want to perform
[Cmd]);
};
I also replaced the constructor with..
if(!window.plugins) {
window.plugins = {};
}
if (!window.plugins.TCPComm) {
window.plugins.TCPComm = new TCPComm();
}
Now when I run it in Chrome, (UI debugging), I can see the plugin built with all the proper functions inside the function.
The Java was fine, I forgot to include the return on the forum code. Whoops.
Now I tried calling the function like I always have and I get a Object # has no method 'exec' at the first JAVASCRIPT call of either Close/Open..
window.plugins.TCPComm.Close("", Dummy, Dummy);
window.plugins.TCPComm.Open(g_IpAddr, OpenOK,OpenFail);
I have breakpoints set in the Java on the execute to let me know when the plugin has called successfully to the Java and still no luck.
Any other thoughts? Thanks again for your insight.

Replace PhoneGap.exec with the following code:
var TCPComm = function() {
};
TCPComm.prototype.Open = function(Cmd,successCallback, failureCallback) {
return cordova.exec( successCallback, //Success callback from the plugin
failureCallback, //Error callback from the plugin
'TCPIPCommPlugin', //Tell PhoneGap to run "DirectoryListingPlugin" Plugin
'Open', //Tell plugin, which action we want to perform
[Cmd]); //Passing list of args to the plugin
};
The add constructor method is deprecated so do:
if(!window.plugins) {
window.plugins = {};
}
if (!window.plugins.videoPlayer) {
window.plugins.TCPComm = new TCPComm();
}
For your Java code you are most of the way there but you need to return the result:
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
PluginResult result = null;
try {
Actions currentAction = Actions.valueOf(action.toUpperCase());
JSONObject Resp = new JSONObject();
String RespStr;
switch(currentAction){
case OPEN:
//do work
this.callbackContext.sendPluginResult(
new PluginResult(PluginResult.Status.OK, results));
} catch (JSONException jsonEx) {
System.out.println(jsonEx.toString());
result = new PluginResult(Status.JSON_EXCEPTION);
}
return true;
}
That should get you upgraded.

Related

asynchronous java method on service layer

I'm using a library called PubNub for posting messages. The PubNub method posts messages asynchronously, and it has a way to see if the message was posted or not.
I'm using Spring MVC and ThymeLeaf, so I would like to send the response back to my front-end after I get the message status (error or success), however, I don't know how to wait until my PubNub method finishes, and then send the result. Here's the code:
#Controller
public class HomeController {
#PostMapping("/triggerDevices")
public String triggerDevices(#ModelAttribute(value = "message") Message message, Model model) {
//
//
// validations and build data
//
//
MyResult result = null;
//Async method
pubNub.publish()
.message(message)
.channel(channel)
.async((result, status) -> {
//This block takes some time
if (status == null || status.isError()) {
//Error case
result = new MyResult (false, status.errorMessage(),message.device);
} else {
//Success case
result = new MyResult (true, null, message.device);
}
});
//Result
model.addAttribute("result", result);
return "home :: info-success";
}
}
I hope someone helps me, thanks so much.
PubNub Java SDK Publish sync
Just use the sync method instead of async
PNPublishResult result = pubnub.publish()
.channel("coolChannel")
.message("test")
.shouldStore(true)
.ttl(10)
.sync();
See full PubNub SDK Java Docs for publish/sync.
That should do it for you.
Cheers!
Using sync is an easy fix! but if u need to keep it async, i would return within the async function result here after you get the result:
//Success case
result = new MyResult (true, null, message.device);
model.addAttribute("result", result);
return "home :: info-success";

Issues with converting java to c#

I'm attempting to convert the code located at How to use signalr in android Service from java to c# and have been making some progress. I'm now stuck at the final method. The java code is:
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mInstance.setmHubConnection();
mInstance.setHubProxy();
ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
Log.e("SimpleSignalR", e.toString());
return;
}
mInstance.sendMessage(MainActivity.unm,"Hello All!");
String CLIENT_METHOD_BROADAST_MESSAGE = "recievedMessage";
mInstance.mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
new SubscriptionHandler2<String,LoginInfo>() {
#Override
public void run(final String msg,final LoginInfo loginInfo) {
final String finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
Intent intent = new Intent();
intent.setAction(MY_ACTION);
intent.putExtra("DATAPASSED", finalMsg);
sendBroadcast(intent);
}
}
, String.class,LoginInfo.class);
}
Using a java to c# converter, this translated to:
private void startSignalR()
{
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mInstance.setmHubConnection();
mInstance.setHubProxy();
ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.Logger);
SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.Start(clientTransport);
try
{
signalRFuture.get();
}
catch (Exception e) when (e is InterruptedException || e is ExecutionException)
{
// Log.e("SimpleSignalR", e.ToString());
return;
}
mInstance.sendMessage("", "Hello All!");
string CLIENT_METHOD_BROADAST_MESSAGE = "recievedMessage";
//String CLIENT_METHOD_BROADAST_MESSAGE = "messageReceived";
mInstance.mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE, new SubscriptionHandler2AnonymousInnerClass(this)
, typeof(string), typeof(LoginInfo));
}
private class SubscriptionHandler2AnonymousInnerClass : SubscriptionHandler2<string, LoginInfo>
{
private readonly SignalRSrv outerInstance;
public SubscriptionHandler2AnonymousInnerClass(SignalRSrv outerInstance)
{
this.outerInstance = outerInstance;
}
//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
//ORIGINAL LINE: #Override public void run(final String msg,final LoginInfo loginInfo)
public override void run(string msg, LoginInfo loginInfo)
{
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final String finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
string finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
Intent intent = new Intent();
intent.Action = MY_ACTION;
intent.PutExtra("DATAPASSED", finalMsg);
sendBroadcast(intent);
}
}
This, of course, generated several errors in Visual Studio 2017.
First, the line Platform.loadPlatformComponent(new AndroidPlatformComponent()); generated the error Platform is inaccessible due to its protection level. Platform in Xamarin for Visual Studio 2017 is indeed protected and is a internal class in System and I cannot change this, so I'm at a loss as how to proceed with it. The same line generates the error The type or namespace name 'AndroidPlatformComponent' could not be found, these errors a numerous and not unexpected I just can't find an equivalent to AndroidPlatformComponent in Visual Studio 2017 so I'm at a loss as how to solve this one.
Next, on this line ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.Logger); generates the error The type or namespace name 'ClientTransport' could not be found, I was also unable to find an equivalent to this and again I'm at a loss as to proceed. Also on this line, .Logger is not defined for the hub connection, apparently it's .getLogger() in java, I was unable to find an equivalent for this one as well.
Next the line SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.Start(clientTransport);' generates the error 1The type or namespace name 'SignalRFuture<>' could not be found, this seemes to be specific to SignalR, again, I am unable to find an equivalent.
The next one has me totally stumped, the line private class SubscriptionHandler2AnonymousInnerClass : SubscriptionHandler2<string, LoginInfo> generates the error The type or namespace name 'SubscriptionHandler2<,>' could not be found. I've looked everywhere online and read up on AnonymousInnerClass, but it was not help with this.
I'm hoping that the users here are more familiar with SignalR and the differences between c# functionality and java functionality. I'm not at all familiar with java nor am I familiar with SignalR and foreground services.
As it turns out, the last method in the java code I was converting was wiring up an event to pass the message received from the hub to the activity. In c# / Visual Studio (2017), that's done very differently which is why I didn't understand/recognize what was going on. So I created a handler in C# and execute a popup message for the message. This in itself may pose problems, but at least I know what's going on. This is the code I wrote to start SignalR from within the service and WireUp the handler:
private void startSignalR()
{
// Company, Department, and section are private variables
// their values are pulled from the intent bundle
// in the OnBind method, that code is:
// Bundle bundlee = intent.GetBundleExtra("TheBundle");
// MyUser = bundlee.GetParcelable("MyUser") as User;
// This information is put into the bundle when the user is logged in.
// I then pass that information to the SignalR client
// when I set the hub connection and placed on the querystring to the hub.
mInstance.setmHubConnection(username, firstname,lastname,company,department,section);
mInstance.setHubProxy();
try
{
// Connect the client to the hup
mInstance.mHubConnection.Start();
// Set the event handler
mInstance.WireUp();
}
catch (System.Exception e) when (e is InterruptedException || e is ExecutionException)
{
ShowMessage("Error: + e.Message)
}
}
This is the WireUp code, this is a method in the client code:
public void WireUp()
{
// set the event handler
mHubProxy.On("broadcastMessage", (string platform, string message) =>
{
if (OnMessageReceived != null)
OnMessageReceived(this, string.Format("{0}: {1}", platform, message));
});
}
As I had anticipated, the popup message won't appear when the app is in the background, so I'm researching a workaround

Creating a basic custom Cordova Plugin

I am quite new in cordova and android native code
I had created my own plugin by using plugman.
plugman create --name myCustomPlugin --plugin_id myCustomPlugin --plugin_version 1.0
plugman had generated all the needed files for me to get started.
js file www/myCustomPlugin.js
var exec = require('cordova/exec');
exports.coolMethod = function(arg0, success, error) {
exec(success, error, "myCustomPlugin", "coolMethod", [arg0]);
};
java file src/android/myCustomPlugin.java, method execute
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("coolMethod")) {
String message = args.getString(0);
this.coolMethod(message, callbackContext);
return true;
}
return false;
}
private void coolMethod(String message, CallbackContext callbackContext) {
if (message != null && message.length() > 0) {
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
The question is:
On the cordova project js file. How do I call myCustomPlugin? and how do I know that it is working?
I am using angular in my cordova project, let say my controller is like this:
.controller('mainCtrl', function($scope){
// how to call myCustomPlugin here?
});
My motive is just to learn how to call and how it work only, maybe after click it will do a native alert or open native view or something.
Thanks in advance!
You can do:
www/myCustomPlugin.js
var MyCustomPlugin {
coolMethod : function(arg0, success, error) {
exec(success, error, "myCustomPlugin", "coolMethod", [arg0]);
}
}
module.exports = MyCustomPlugin
And in your js client just:
MyCustomPlugin.coolMethod("Arg1", function(){}, function(){});
Cordova will inject JavaScript file for you.
Hope it helps.

Phonegap jabber plugin for android

For jabber support i use library Smack. Android port asmack.
I have class SmackAPI which implements MessageListener interface and contains methods to connect, login, send message. In the same time this class contains method:
#Override
public void processMessage(Chat chat, Message message) {
String from = message.getFrom();
String body = message.getBody();
System.out.println(String.format("Received message '%1$s' from %2$s", body, from));
this.recievedMessage = message;
}
It provides by MessageListener interface. All new messages processed by this method.
I write jabber plugin to connect, login, send message from phonegap.
My question: how i can in javascript listen for new messages?
I did it. I dont know however it is right way, but it works!
Cordova plugin class:
public class SmackJabber extends CordovaPlugin {
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
this.cbContext = callbackContext;
switch (action) {
case LISTEN_MESSAGE:
res = new PluginResult(PluginResult.Status.NO_RESULT);
res.setKeepCallback(true);
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
String callbackId = cbContext.getCallbackId();
while (true) {
String msg = getMsg();
if (msg != null) {
res = new PluginResult(PluginResult.Status.OK, msg);
res.setKeepCallback(true);
CallbackContext cb = new CallbackContext(callbackId, webView);
cb.sendPluginResult(res);
}
}
}
});
cbContext.sendPluginResult(res);
break;
And easy javascript. Just call plugin method:
window.plugins.smackJabber.listenMessage(function(result) {
alert(result)
}, function(error) {
alert(error)
}
);
Explanation:
I call plugin method "listenMessage" (calling "execute" method with action "LISTEN_MESSAGE"). There i start thread from cordova threadpool with runnable, in runnable i got recursive function which check message. But before start runnable i have to take callbackId of method who call method execute. Also, for exit from method, i create new PluginResult with status "NO_RESULT" and set it option "keepCallback" to true - it means, that method calls in javascript awaiting one more callback result from me. When i got message, i create new callbackcontext based on callbackid and my webview, do setKeepCallback to true for futher possible responses for pluginresult, putting in pluginresult my message with status "OK" and sending it to callbackcontext. That's all.

how can i display progress bar for dailymotion cloud uploading

I am using Dailymotion cloud in my android app to upload videos to server.
i want to display progress bar while uploading but i don't know how can i get byte by byte value to update progress bar.
This is dailymotion cloud api link Dailymotion cloud api link
While searching on internet i found this progress bar in java but i don't know how can i implement into this method of dailymotion api.
I am using async task to display progress bar
Here is android code for uploading
try
{
CloudKey cloud = new CloudKey(user_id, api_key);
File f = new File(selectedVideoPath);
String media_id = cloud.mediaCreate(f);
System.out.println(media_id);
Log.d("Testing", "media_id is"+media_id);
}
And here is Dailymotion API's Cloud.class mediacreate() in which i want to display progress bar .. any idea
public String mediaCreate(File f) throws Exception
{
return this.mediaCreate(f, null, null);
}
public String mediaCreate(File f, DCArray assets_names, DCObject meta) throws Exception
{
String upload_url = this.fileUpload();
PostMethod filePost = null;
int status;
try
{
filePost = new PostMethod(upload_url);
Part[] parts = {
new FilePart("file", f)
};
filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
HttpClient client = new HttpClient();
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
status = client.executeMethod(filePost);
if (status == HttpStatus.SC_OK)
{
ObjectMapper mapper = new ObjectMapper();
DCObject json_response = DCObject.create(mapper.readValue(filePost.getResponseBodyAsString(), Map.class));
return this.mediaCreate(json_response.pull("url"), assets_names, meta);
}
else
{
throw new DCException("Upload failed.");
}
}
catch (Exception e)
{
throw new DCException("Upload failed: " + e.getMessage());
}
finally
{
if (filePost != null)
{
filePost.releaseConnection();
}
}
}
I'm not able to find any api support for doing this with the DailyMotion class that you mentioned.
If you can edit the source of that library, then you could try extending MultipartRequestEntity and add support for callbacks for progress, and then just plug in that new class in the DailyMotion code in the mediaCreate method:
filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
.. replace MultipartRequestEntity by the new one, eg. ExtendedMultipartRequestEntity.
See the answer by Tuler and others at File Upload with Java (with progress bar) to see how to do it.
Once you are getting updates via the callback, then you can hook up progress bar.

Categories