Barcode scanner plugin windows phone 8 doesnt execute callback - javascript

Hello im trying to use the cordoba plugin for barcode scanner windows phone 8, using mobilefirst 7.1, and after the plugin read de barcode correctly (i just put some breakpoints and the e.Barcode have the barcode value), the plagin
private void TaskCompleted(object sender, BarcodeScannerTask.ScanResult e)
{
PluginResult result;
switch (e.TaskResult)
{
case TaskResult.OK:
result = new PluginResult(PluginResult.Status.OK, JsonHelper.Serialize(new BarcodeResult(e.Barcode)));
// result.Message = ;
break;
case TaskResult.Cancel:
// If scan is cancelled we return PluginResult.Status.OK with Message contains cancelled: true
// See plugin docs https://github.com/MSOpenTech/BarcodeScanner#using-the-plugin
result = new PluginResult(PluginResult.Status.OK, JsonHelper.Serialize(new BarcodeResult()));
// result.Message =;
break;
default:
result = new PluginResult(PluginResult.Status.ERROR,"Error default");
break;
}
DispatchCommandResult(result);
}
the code enters to TaskResult.OK, and then create the response object correctly, next: execute DispatchCommandResult(result) and returns to my javascript code, but the callbacks funtions were never called.
Any help?

Because you did not provide the web part (the JS implementation) it is difficult to know why it is not calling the callback function.
My suggestion to you then is to look at the Cordova plug-ins tutorial for Windows Phone 8 and verify that you have implemented the JS part correctly.
See here: https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/7.1/adding-native-functionality/windows-phone-8-adding-native-functionality-hybrid-application-apache-cordova-plugin/
function sayHello() {
var name = $("#NameInput").val();
cordova.exe(sayHelloSuccess, sayHelloFailure, "SayHelloPlugin", "sayHello", [name]);
}
function sayHelloSuccess(data){
WL.SimpleDialog.show(
"Response from plug-in", data,
[{text: "OK", handler: function() {WL.Logger.debug("Ok button pressed");}}]
);
}
function sayHelloFailure(data){
WL.SimpleDialog.show(
"Response from plug-in", data,
[{text: "OK", handler: function() {WL.Logger.debug("Ok button pressed");}}]
);
}

Related

Using JavaScript with WkWebView - error on UserMessageHandler

When sending a message through Javascript to iOS, I encountered this error message that I can't find any information online: "Can only call UserMessageHandler.postMessage on instances of UserMessageHandler".
I am using a webview to render a webpage on iOS.
I tried adding the same script from native code and I was able to receive the message. However, the same script shows the above error if I deploy it on the web site.
let scriptSource = "window.webkit.messageHandlers.jsHandler.postMessage({command: 'command goes here'});"
let userScript = WKUserScript(source: scriptSource, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
userContentController.addUserScript(userScript)
on the web end, I used the following code
key: "onExit",
value: function() {
var t = function() {
try {
return window.webkit.messageHandlers.jsHandler.postMessage || null
} catch (t) {
return null
}
}();
if (t)
try {
t({
command: "command goes here"
}), console.log("window.webkit.messageHandlers.jsHandler.postMessage called successfully")
} catch (t) {
console.log("error thrown when calling window.webkit.messageHandlers.jsHandler.postMessage - " + (t || {}).message)
}
else
console.log("window.webkit.messageHandlers.jsHandler.postMessage not found!")
}
Explicit bind this will resolve the error:
window.webkit.messageHandlers.jsHandler.postMessage.bind(window.webkit.messageHandlers.jsHandler)

Can't Get Error To Return To Ionic/Cordova App From Objective C Plugin

I have written a plugin for a bluetooth zebra printer. I can make it work and it prints fine, but I am needing to return an error back to my app if the printer is either off or not connected. I'm able to get this to open in an alert directly from Objective C, but I really need to return the error back to my mobile app so I can create new actions for the user if it does error out.
The code compiles and builds, but when I run the code it does not return the error back to my javascript error function. Keep in mind I'm not very familiar with Objective C and am working my way through this.
Here is the Objective C code that should be sent back to the app (I can see that the code steps into this function, but doesn't get sent back) :
__block CDVPluginResult* result; //Declared at the beginning of the print function in .m file
dispatch_async(dispatch_get_main_queue(), ^{
if(success != YES || error != nil) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
messageAsString:[NSString stringWithFormat:
#"Either the printer is turned off or not connected "]];
}
});
Here is my javascript function where I initiate the call to the printer.
$scope.printTicket = function () {
$ionicPlatform.ready(function () {
cordova.plugins.zebra.printer.sendZplOverBluetooth($scope.printObj, function successCallback () {
console.log('SUCCESS: Print');
}, function errorCallback () {
console.log('ERROR: Print');
});
})
}
Any help greatly appreciated.
You need to actually send the plugin result after creating it with sendPluginResult - something like:
- (void) yourPluginFunction: (CDVInvokedUrlCommand*)command
{
__block CDVPluginResult* result; //Declared at the beginning of the print function in .m file
dispatch_async(dispatch_get_main_queue(), ^{
if(success != YES || error != nil) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
messageAsString:[NSString stringWithFormat:
#"Either the printer is turned off or not connected "]];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
});
}

How to save an image in Windows Phone 8.1 using WinJS

I am looking to migrate my Windows 8 app to Windows Phone 8.1 using WinJS. I had used picker.pickSaveFileAsync in Windows 8 which is not supported for WP 8.1.
I had then referred the official samples from http://code.msdn.microsoft.com/windowsapps/Simple-Imaging-Sample-a2dec2b0
The Javascript version in the sample does not save on Windows Phone 8.1 when the Save As button is clicked and it returns the below error when `getFileAsync is called:
0x80004005 - JavaScript runtime error: Unspecified error
When clicked on Save, it returns a Read Only error. I had tested the sample in Lumia 520 also. I get the same error in the phone.
In Windows Phone you cannot get write access to files returned from a FileOpenPicker. You have to use a FileSavePicker to do this. With the help of a coworker I was able to get a sample working that can open and then re-save a file under a new name starting from the "Blank" Windows Phone App template
Inside of your default.html create two buttons:
<button id="choose">Choose a Photo</button>
<button id="save">Save a Photo</button>
Replace default.js with the following:
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
var origFile = null;
function pickPhoto() {
var picker = new Windows.Storage.Pickers.FileOpenPicker();
var enumerator = Windows.Graphics.Imaging.BitmapDecoder.getDecoderInformationEnumerator();
enumerator.forEach(function (decoderInfo) {
decoderInfo.fileExtensions.forEach(function (fileExtension) {
picker.fileTypeFilter.append(fileExtension);
});
});
picker.pickSingleFileAndContinue();
}
function loadPhoto(file) {
origFile = file;
}
function savePhotoPicker(file) {
var picker = new Windows.Storage.Pickers.FileSavePicker();
picker.fileTypeChoices.insert("JPEG file", [".jpg"]);
picker.pickSaveFileAndContinue();
}
function savePhoto(src, dest) {
src.copyAndReplaceAsync(dest).done(function () {
console.log("success");
})
}
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
document.getElementById("choose").addEventListener("click", pickPhoto);
document.getElementById("save").addEventListener("click", savePhotoPicker);
}
if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.pickFileContinuation) {
loadPhoto(args.detail.files[0]);
}
if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.pickSaveFileContinuation) {
savePhoto(origFile, args.detail.file);
}
};
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
app.start();
})();
If you are creating the file yourself, make sure to set the ImageProperties for it before saving.
Sorry about the broken sample, I'll get that reported to the sample owner.

ASP.Net ThreadPool Delegate Callback -- JavaScript Not Firing On Callback Thread

I have searched for several days now, and have tried about every solution that I could find. I know this is something I am not doing correctly, however, I am not sure what the correct way is.
I have an ASP.Net C# web site, running on .Net Framework 4.5. I have a link button on a form, that when clicked fires off a long running process using the ThreadPool. I have a delegate callback setup, and the code does fire when the process is canceled or when it finishes. (I am using the Cancelation Token for canceling the process and the process is Active Reports in case that matters.)
Like I said, everything works great, except for when the callback code fires it does not execute the javascript. (FYI -- this is NOT a javascript callback, just trying to fire off some javascript code when the process finishes.)
Here is the code that i start the report...
string sThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
ThreadPool.QueueUserWorkItem(new WaitCallback(StartReport), cts.Token);
Here is the code for the StartReport....
public static void StartReport(object obj) {
try {
OnTaskCompleteDelegate callback = new OnTaskCompleteDelegate(OnTaskComplete);
BoyceReporting.CallReport(boyce.BoyceThreadingEnvironment.OBRO, "THREADING");
if (boyce.BoyceThreadingEnvironment.CTS.Token.IsCancellationRequested) {
boyce.BoyceThreadingEnvironment.SESSION.sScriptToExecute = "alert('Report Canceled By User');";
callback("CANCELED");
} else {
callback("FINISHED");
}
} catch {
throw;
}
}
Here is the code for the CallBack code.....
public static void OnTaskComplete(string ReportResult) {
try {
sReportResult = ReportResult;
if (ReportResult == "CANCELED") {
// In case we need to do additional things if the report is canceled
}
string sThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
boyce.BoyceThreadingEnvironment.THISPAGE.ClientScript.RegisterStartupScript(boyce.BoyceThreadingEnvironment.THISPAGE.GetType(), "FireTheScript" + DateTime.Now.ToString(), boyce.BoyceThreadingEnvironment.SESSION.sScriptToExecute, true);
ScriptManager.RegisterStartupScript(boyce.BoyceThreadingEnvironment.THISPAGE, boyce.BoyceThreadingEnvironment.THISPAGE.GetType(), "DisplayReport" + DateTime.Now.ToString(), boyce.BoyceThreadingEnvironment.SESSION.sScriptToExecute, true);
} catch {
throw;
}
}
Here is the issue that I am having.....
Everything works fine except i can not get the last line of code to fire the script.
ScriptManager.RegisterStartupScript
Here is what I think is happening.....
From looking at the thread ID, I am sure the reason that the code is not firing is because the ScriptManager code that I am trying to fire in the Call Back event is on a different thread, other than the main thread.
Here is my question(s).....
(1) Am I correct in why this is not firing the JavaScript
(2) How can I (from inside of the CallBack) get this JavaScript to fire? Is there a way to force this to execute on the main Thread?
It's not firing in JS because you're spinning off a new thread. In the meantime, the request has long since returned to the client and closed the connection. By the time the thread tries to write something out to the Response, it's already finished.
Instead of doing it this way, just have your button click (or whatever it is that kicks off the report), inside of an UpdatePanel. Then, you don't need to fire off a new thread.
Here is the cod I used in the C# Code Behind to call the web service to start monitoring this process.
----------------------------------------------------------------------------------------------
CurrentSession.bIsReportRunning = true;
ScriptManager.RegisterStartupScript(this, this.GetType(), "WaitForReport" + DateTime.Now.ToString(), "jsWaitOnCallReport();", true);
MultiThreadReport.RunTheReport(HttpContext.Current, CurrentSession, this, oBRO);
Here is the code that calls the method, using the threadpool, and the method called..
----------------------------------------------------------------------------------------------
ThreadPool.QueueUserWorkItem(new WaitCallback(StartReport), cts.Token);
public static void StartReport(object obj) {
try {
OnTaskCompleteDelegate callback = new OnTaskCompleteDelegate(OnTaskComplete);
BoyceReporting.CallReport(boyce.BoyceThreadingEnvironment.OBRO, "THREADING");
HttpContext.Current = boyce.BoyceThreadingEnvironment.CONTEXT;
if (boyce.BoyceThreadingEnvironment.CTS.Token.IsCancellationRequested) {
boyce.BoyceThreadingEnvironment.SESSION.sScriptToExecute = "alert('Report Canceled By User');";
boyce.BoyceThreadingEnvironment.SESSION.bIsReportRunning = false;
callback("CANCELED");
} else {
boyce.BoyceThreadingEnvironment.SESSION.bIsReportRunning = false;
callback("FINISHED");
}
} catch {
throw;
}
}
Here is the web service method I created to monitor the process, with a built in safety net
--------------------------------------------------------------------------------------------
[WebMethod(EnableSession = true)]
public string WaitOnReport() {
try {
HttpContext.Current = boyce.BoyceThreadingEnvironment.CONTEXT;
SessionManager CurrentSession;
CurrentSession = (SessionManager)boyce.BoyceThreadingEnvironment.SESSION;
DateTime dtStartTime = DateTime.Now;
DateTime dtCurrentTime = DateTime.Now;
if (CurrentSession != null) {
do {
// Build a safety limit into this loop to avoid an infinate loope
// If this runs longer than 20 minutes, then force an error due to timeout
// This timeout should be lowered when they find out what the issue is with
// the "long running reports". For now, I set it to 20 minutes but shoud be MUCH lower.
dtCurrentTime = DateTime.Now;
TimeSpan span = dtCurrentTime-dtStartTime;
double totalMinutes = span.TotalMinutes;
if (totalMinutes>=20) {
return "alert('Error In Creating Report (Time-Out)');";
}
} while (CurrentSession.bIsReportRunning == true);
// If all goes well, return the script to either OPEN the report or display CANCEL message
return CurrentSession.sScriptToExecute;
} else {
return "alert('Error In Creating Report (Session)');";
}
} catch {
throw;
}
}
And here is the JavaScript code I used to initiate the Web Service Call and Also The Postback
--------------------------------------------------------------------------------------------
function jsWaitOnCallReport() {
try {
var oWebService = BoyceWebService.WaitOnReport(jsWaitOnCallReport_CallBack);
} catch (e) {
alert('Error In Calling Report Screen -- ' + e);
}
}
function jsWaitOnCallReport_CallBack(result) {
try {
eval(result);
var myExtender = $find('ModalPopupExtenderPROGRESS');
if (myExtender != null) {
try {
myExtender.hide();
} catch (e) {
// Ignore Any Error That May Be Thrown Here
}
}
$find('PROGRESS').hide();
} catch (e) {
alert('Error In Opening Report Screen -- ' + e);
}
}
Hope this helps someone else out.. Like I said, I am not sure this is the best solution, but it works.. I would be interested in other solutions for this issue to try... Thanks.

External interface and Internet Explorer 9 issue

Boy-oh-boy do I hate external interface. I have a video player that utilizes external interface to control the flash object and to allow the flash object to pass messages to the same javascript. For a time it worked well in all browsers. Then a few days ago i went to go test it in all browsers before i moved the project out of development, and found that the application broke in internet explorer 9. The following error appeared in the console:
SCRIPT16389: Could not complete the operation due to error 8070000c.
jquery.min.js, line 16 character 29366
My javascript file is really long but here are the important parts. All my actions are contained in an object that i created. Inside one of my methods i have the following lines:
var that = this;
that.stop();
here are all the methods that get called as a result of that method:
this.stop = function(){
var that = this;
console.log('stop called');
that.pause();
that.seek(0);
that.isPlaying = false;
console.log('stop finished');
};
this.pause = function(){
var that = this;
console.log('pause called');
if(that.player == 'undefined' || that.player == null){
that.player = that.GetMediaObject(that.playerID);
}
that.player.pauseMedia(); //external interface call
that.isPlaying = false;
console.log('pause finished');
};
this.seek = function(seek){
var that = this;
console.log('seek called');
if(that.player == 'undefined' || that.player ==null){
console.log("player="+that.player+". resetting player object");
that.player = that.GetMediaObject(that.playerID);
console.log("player="+that.player);
}
that.player.scrubMedia(seek); //external interface call
console.log('seek finished');
};
//this method returns a reference to my player. This method is call once when the page loads and then again as necessary by all methods that make external interface calls
this.GetMediaObject = function(playerID){
var mediaObj = swfobject.getObjectById(playerID);
console.log('fetching media object: ' +mediaObj );
//if swfobject.getObjectById fails
if(typeof mediaObj == 'undefined' || mediaObj == null){
console.log('secondary fetch required');
var isIE = navigator.userAgent.match(/MSIE/i);
mediaObj = isIE ? window[playerID] : document[playerID];
}
return mediaObj;
};
Here's the output from my console.log statments:
LOG: fetching media object: [object HTMLObjectElement]
LOG: video-obj-1: ready
LOG: stop called
LOG: pause called
LOG: pause finished
LOG: seek called
LOG: player=[object HTMLObjectElement]
SCRIPT16389: Could not complete the operation due to error 8070000c.
jquery.min.js, line 16 character 29366
The interesting thing is that it appears that the first external interface call 'that.player.pauseMedia()' doesn't have any issue, but the subsequent call to 'that.player.scrubMedia(0)' fails. Another odd thing is that it points to jquery as the source of the error, but there's no call to jquery in those functions.
Here's what i know it's not. It is not an issue where my timing is off. The last line of my actionscript sends a message to the javascript when the flash object has completely loaded. Also i set the parameter 'allowScriptAccess' to 'always' so it's not that either. The actionscript file we use has been used in previous projects so i am 90% certain that that is not the issue.
here's my actionscript anyways. I didn't write actionscript and i'm not too familiar with the language but I tried to put in the parts that seemed most pertinent to my application:
flash.system.Security.allowDomain("*.mydomain.com");
import flash.external.ExternalInterface;
// variables to store local information about the current media
var mediaEmbedServer:String = "www";
var mediaPlayerID:String;
var mediaFile:String;
var mediaDuration:Number;
// variables to be watched by actionscript and message javascript on changes
var mediaPositions:String = "0,0"; // buffer position, scrub position
var mediaStatus:String;
var netStreamClient:Object = new Object();
netStreamClient.onMetaData = metaDataHandler;
netStreamClient.onCuePoint = cuePointHandler;
var connection:NetConnection;
var stream:NetStream;
var media:Video = new Video();
// grab the media's duration when it becomes available
function metaDataHandler(info:Object):void {
mediaDuration = info.duration;
}
function cuePointHandler(info:Object):void {
}
connection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
try {
var paramName:String;
var paramValue:String;
var paramObject:Object = LoaderInfo(this.root.loaderInfo).parameters;
for (paramName in paramObject) {
paramValue = String(paramObject[paramName]);
switch (paramName){
case "server":
mediaEmbedServer = paramValue;
break
case "playerID":
mediaPlayerID = paramValue;
break
}
}
} catch (error:Error) {
}
if (mediaEmbedServer == "dev" || mediaEmbedServer == "dev2"){
connection.connect("rtmp://media.developmentMediaServer.com/myApp");
} else {
connection.connect("rtmp://media.myMediaServer.com/myApp");
}
function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
function connectStream():void {
stream = new NetStream(connection);
stream.soundTransform = new SoundTransform(1);
stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
stream.client = netStreamClient;
media.attachNetStream(stream);
media.width = 720;
media.height = 405;
addChild(media);
}
function netStatusHandler(stats:NetStatusEvent){
switch (stats.info.code){
case "NetConnection.Connect.Success":
connectStream();
break;
case "NetConnection.Call.BadVersion":
case "NetConnection.Call.Failed":
case "NetConnection.Call.Prohibited":
case "NetConnection.Connect.AppShutdown":
case "NetConnection.Connect.Failed":
case "NetConnection.Connect.InvalidApp":
case "NetConnection.Connect.Rejected":
case "NetGroup.Connect.Failed":
case "NetGroup.Connect.Rejected":
case "NetStream.Connect.Failed":
case "NetStream.Connect.Rejected":
case "NetStream.Failed":
case "NetStream.Play.Failed":
case "NetStream.Play.FileStructureInvalid":
case "NetStream.Play.NoSupportedTrackFound":
case "NetStream.Play.StreamNotFound":
case "NetStream.Seek.Failed":
case "NetStream.Seek.InvalidTime":
// report error status and reset javascriptPlay
clearInterval(progressInterval);
messageStatus("error");
break;
default:
// check time through file to determine if media is over
if (stream.time > 0 && stream.time >= (mediaDuration - .25)){
// reset media if it has ended
clearInterval(progressInterval);
stream.play(mediaFile, 0, 0);
messageStatus("finished");
}
}
};
var progressInterval:Number;
// respond to a play/pause request by playing/pausing the current stream
function pauseMedia(){
clearInterval(progressInterval);
if (mediaStatus == 'playing'){
stream.pause();
messageStatus("paused");
}
};
ExternalInterface.addCallback( "pauseMedia", pauseMedia );
// respond to a scrub request by seeking to a position in the media
function scrubMedia(newPosition){
clearInterval(progressInterval);
if (mediaStatus == "playing"){
stream.pause();
messageStatus("paused");
}
stream.seek(newPosition * mediaDuration);
var positionSeconds = newPosition * mediaDuration;
messagePositions(positionSeconds+","+positionSeconds);
};
ExternalInterface.addCallback( "scrubMedia", scrubMedia );
ExternalInterface.call("MediaPlayerReady", mediaPlayerID);
Sounds like an undefined expando property which may be caused by a jQuery IE9 bug. The best way to debug it is to remove the userAgent test and replace it with a check for the object element, such as:
document.getElementsByTagName("object")[0].outerHTML
to see whether the ID attribute is being changed after the first click by jQuery.
I had this problem using JPEGCam, which also uses flash's external interface. My webcam control was being loaded dynamically within a div, and would then throw this error in IE (not firefox or chrome). After moving the initialization of my flash control to document.ready in the parent page, then hiding/showing/moving the control as needed, i was able to work around this exception.
Hope that helps.

Categories

Resources