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)
Related
The problem only occurs in the compiled application, so I guess it's a browser specific specific problem, but I'm not sure:
I have added the following script to a webpage:
async function exportChatAsXMLHelper(params){
let displayname = params[0];
let includeMedia = params[1];
let debug = params[2];
await exportChatAsXML(displayname, includeMedia, debug);
}
async function exportChatAsXML(displayname, includeMedia, debug)
{
let chat = (await WPP.chat.list()).find(m => m.contact && m.contact.name && m.contact.name.includes(displayname));
await WPP.chat.openChatBottom(chat.id);
let msgs = await WPP.chat.getMessages(chat.id, {count : -1});
const log = (obj) => debug && console.log(obj);
log('Total messages: ' + msgs.length);
let count=msgs.length;
for (var i = 0; i < count; i++) {
log('Message number: ' + i);
let message = msgs[i];
let xml='';
xml+= '<message>';
xml+= '<sender>'+ message.from.user +'</sender>';
xml+= '<receiver>'+ message.to.user +'</receiver>';
xml+= '<type>'+ (message.type || '') +'</type>';
if(message.type == 'chat')
{
xml+= '<body>'+ message.body +'</body>';
}
if(message.type != 'chat' && includeMedia)
{
xml+= '<media>';
xml+= '<caption>'+ (message.caption || '') +'</caption>';
xml+= '<filename>'+ (message.filename || '') +'</filename>';
log('Downloading media');
try
{
let mediabody = await mediatoBase64(message.id);
xml+= '<MediaDownloadStatus>success</MediaDownloadStatus>';
xml+= '<base64>'+ mediabody +'</base64>';
}
catch(e)
{
xml+= '<base64></base64>';
xml+= '<MediaDownloadStatus>fail</MediaDownloadStatus>';
}
xml+= '</media>';
}
xml+= '</message>';
alert('before'); //this is still shown
//where is JSCallbackReceiver defined? it is from vb6
window.JSCallbackReceiver.OnWhatsAppXMLReceived(i, count, xml);
alert('after'); //this is not shown
xml='';
}
}
//-----
async function mediatoBase64(msgid) {
let blob = await WPP.chat.downloadMedia(msgid);
return new Promise((resolve, _) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
It works fine on my developer's machine, but throws an error on a client's machine:
Uncaught (in promise) TypeError: Cannot read property 'OnWhatsAppXMLReceived' of undefined https://web.whatsapp.com/ 80
I have added some alerts now to see where exactely it goes wrong.
The alert "before" is shown, the alert "after" is not shown, so the error definitively occurs in
window.JSCallbackReceiver.OnWhatsAppXMLReceived(i, count, xml);
alert('after');
What could I check to see what exactely goes wrong / what is different on the client's machine?
The callback object is defined in VB6 like this:
Private m_JSCallback As clsJSCallbackReceiver
Set m_JSCallback = New clsJSCallbackReceiver
Me.webkit1.AddObject "JSCallbackReceiver", m_JSCallback
Does the error message mean that the browser does not find the object that I added via AddObject?
I am using mobileFx webkit browser which is based on Chromium, but I guess that is not important.
This is what the class clsJSCallbackReceiver looks like in VB6:
Option Explicit
Public Sub OnWhatsAppXMLReceived(ByVal uIndex As Long, ByVal uCount As Long, ByVal uXml As String)
Debug.Print("I was called!")
End Sub
Public Sub SaySomething(ByVal u As String)
MsgBox(u)
End Sub
Thank you!
Edit:
I only happens when compiled.
When I run it in the VB6 IDE, it works fine.
After the error occurs, I can still call
m_JSCallback.SaySomething("Hello!")
, and it will work.
So the object is still alive.
It is just not connected to the browser, I guess.
I found this document, which says this about an example they've given:
"Next, since the Instancing property of the class is PublicNotCreatable, the project must provide a way for a client to instantiate the object. Add a new function in a standard module. Where clsEmployee is the name of the class of interest. Also, this should not be a private module."
And your code seems to contradict that.
The error message explain you that at the line:
window.JSCallbackReceiver.OnWhatsAppXMLReceived(i, count, xml);
the window.JSCallbackReceiver object is undefined.
First to get rid of this error message you chould replace this line with:
if (window.JSCallbackReceiver) {
window.JSCallbackReceiver.OnWhatsAppXMLReceived(i, count, xml);
}
This will not solve you problem, because it just suppress error.
So you then need to investigate why SCallbackReceiver is undefined on your customer's browser.
To get more help, you need to provide source code about JSCallbackReceiver.
I want to use web worker to handle my zipcode checker function, I haven't worked with web worker before so the concept is new to me
This is my zipcode function
``
function checkZipCode() {
event.preventDefault();
if(document.getElementById('zipcode').value < 20000) {
document.getElementById('zip-result').innerHTML = 'Sorry, we haven’t expanded to that area yet';
} else if (document.getElementById('zipcode').value >= 20000) {
document.getElementById('zip-result').innerHTML = 'We’ve got your area covered!'
} else {
return null
}
};
As per the docs workers are pretty easy to spin up:
//in a JS file
const myWorker = new Worker('./myWorker.js');//worker requested and top-level scope code executed
myWorker.postMessage('hello');
myWorker.addEventListener('message', e => {
//e.data will hold data sent from worker
const message = e.data;
console.log(message); // HELLO
//if it's just a one-time thing, you can kill the worker
myWorker.terminate();
}
myWorker.addEventListener('error', e => {//worker might throw an error
e.preventDefault();
console.log(e.message, `on line ${e.lineno}`);
});
//myWorker.js
//run whatever you need, just no DOM stuff, no window etc
console.log('this line runs when worker loads');
addEventListener('message', (e) => {
postMessage(e.data.toUpperCase());//up-case message and send it right back
});
And I wish the following objective:
assign an event to the hotmail calendar
I have the following code:
using Microsoft.Live;
private void editEvent()
{
try
{
var authClient = new LiveAuthClient();
LiveLoginResult result = await authClient.LoginAsync(new string[] { "wl.signin", "wl.calendars", "wl.calendars_update" });
if (result.Status == LiveConnectSessionStatus.Connected)
{
var eventToPost = new Dictionary<string, object>();
eventToPost.Add("name", "program my c# - 2nd trial");
eventToPost.Add("calendar_id", "calendar.136c10ca65544801.99c35f9a9fb341a3af35daa82f4569f8");
eventToPost.Add("description", "this should be 2nd calendar");
eventToPost.Add("start_time", "2019-09-10T01:30:00-08:00");
eventToPost.Add("end_time", "2019-09-12T03:00:00-08:00");
eventToPost.Add("location", "business placeeeeeee");
eventToPost.Add("is_all_day_event", false);
eventToPost.Add("availability", "busy");
eventToPost.Add("visibility", "public");
this.session = result.Session;
connected = true;
this.connectClient = new LiveConnectClient(result.Session);
var meResult = await connectClient.PutAsync("event.136c10ca6a355671.5f21a7994c7e40fd800bc48dcc07300b.991d1912ec6b4523a0f08839992aa2bb", eventToPost);
meData = meResult.Result;
}
}
catch (LiveAuthException ex)
{
// Display an error message.
}
catch (LiveConnectException ex)
{
// Display an error message.
infoTextBlock.Text += ex.Data + " ..." + ex.Message;
}
}
In which I try to test it to see how it works and if it fulfills the desired objective.
But I do not know which library works LiveAuthClient and LiveConnectSessionStatus
Download the nuget package live sdk package, but it still shows error in LiveAuthClient and LiveConnectSessionStatus
I would like to know which library should download to test its operation, since I want to add an event to the Hotmail calendar with C # or Javascript. If anyone knows, or if you have an example, I would greatly appreciate it.
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];
}
});
}
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");}}]
);
}