-
-
Save acegreen/05282d20eb45de8d30d5 to your computer and use it in GitHub Desktop.
let script: JSValue = jsContext.objectForKeyedSubscript("getImageURL") | |
[jsContext callWithArguments:@["FirstParam",^(NSString* callbackValue) { | |
NSLog(@"Got a value: %@",callbackValue) | |
}] | |
basically I have a javascript function that looks like this: | |
function getImageURL(object, callback) { | |
object.executeActionById("takeScreenshot"); | |
object.onScreenshotReady(function(imageName) { | |
alert(imageName); | |
callback(imageName); | |
}); | |
}; | |
And all I really want is imageName on the iOS side. So I'm trying to call the callback part of it on iOS and get imageName. | |
onScreenshotReady is async so I need to wait for it to finish before I get my imageName. So I created a callback within it |
Should be just
script.callWithArguments(["widget", { imageName: String in
// Got image
}])
@jackwu95 first off thanks for the reply.
I tried that and still getting an issue.
I also tried
script.callWithArguments(["widget", { (imageName: String) in
// Got image
}])
brackets around (imageName: String) but its still too ambiguous.
I see. Read this http://nshipster.com/javascriptcore/
Yea I saw that link but can't get it to work. .callWithArguments wants an array and I'm trying to add a callback block to it.
This is as far as I have come now. Swift needs to be converted to @objc_block (now called convention(block). Doesn't execute getImageURL though because no image or alert is generated. Also doesn't print on iOS
let script: JSValue = jsContext.objectForKeyedSubscript("getImageURL")
print(script)
let simplifyString: @convention(block) String -> String = { imageName in
print(imageName)
return imageName
}
let unsafeString = unsafeBitCast(simplifyString, AnyObject.self)
script.callWithArguments(["widget", unsafeString])
print(script) shows the correct function:
function getImageURL(object, callback) {
object.executeActionById("takeScreenshot");
object.onScreenshotReady(function(imageName) {
alert(imageName);
callback(imageName);
});
}
Looks like any remaining problems may be in your Javascript -- this is working properly for me:
// set up context
let context = JSContext()
context.exceptionHandler = { context, exception in
print("JS Error: \(exception)")
}
// two functions:
// immediately calls the callback with the first argument
context.evaluateScript("var test = function(object, callback) { callback('test ' + object); }")
// calls the first function with a function literal that calls the callback
// this one better emulates the flow of getImageTest
context.evaluateScript("var nestedTest = function(object, callback) { test(object, function(nestedObject) { callback('nestedTest ' + nestedObject); }); }")
// create the callback and cast to AnyObject
let callback: @convention(block) String -> () = { imageName in
print(imageName)
}
let args = ["Hello from JS!", unsafeBitCast(callback, AnyObject.self)]
context.objectForKeyedSubscript("test").callWithArguments(args)
// prints "test Hello from JS!"
context.objectForKeyedSubscript("nestedTest").callWithArguments(args)
// prints "nestedTest test Hello from JS!"
Hi @natecook1000 first off thanks for the reply.
With the code in my last reply. I can print(script) and it prints the right function. But the callWithArguements doesn't do anything.
I can execute the getImageURL with the following and it actually alerts the imageName
let script = "getImageURL(widget, function(imageName) { })"
jsContext.evaluateScript(script)
but on iOS this doesn't wait for a return before executing the rest. so I don't think my function is wrong is it?
By the way my getImageURL isn't in a variable like var test = its just in index.html while I'm loading in my webView and passing it to my jsContext. and it prints it correctly.
I GOT IT!!!!!!!! :)
π π π π
What did the trick?
I added the exceptionHandler to see if I get any errors:
And turns out I did. "widget" was not being passed along so the function was executing
object.executeActionById("takeScreenshot");
object.onScreenshotReady(function(imageName) ....
instead of
widget.executeActionById("takeScreenshot");
widget.onScreenshotReady(function(imageName) ....
So since I actually don't need to pass that parameter from iOS. I just hardcoded it directly. so my function became:
function getImageURL(callback) {
widget.executeActionById("takeScreenshot");
widget.onScreenshotReady(function(imageName) {
callback(imageName);
});
};
and on iOS side i did:
let args = [unsafeBitCast(callback, AnyObject.self)]
jsContext.objectForKeyedSubscript("getImageURL").callWithArguments(args)
And works exactly as expected.
Many many thanks for feedback. Spent two days on this pesky issue. Now onto the next
HI @acegreen,
How can I save an image to my local("Downloads") without using the snapshot url from tradingview?
Hi @acegreen,
In addition to my first question, how can I create a method that will not generate an image on tradingview, but generating a base64 image and saving it to my local directory.
Thanks in advance..=
I tried the following: