So I have this function on my site:
function appQrHandlerSet(result) {
jQuery(function() {
jQuery('#readed_qr_url').val(result.url);
jQuery(this).getLayerForm('#qr_handler_layer');
});
}
From the iOS app, I have to call this function and pass a JSON to it, how can I achieve that?
I've been trying to make it work for 3 days now, but I gave up because something is not working right.
Thanks in advance!
According to your code, the parameter result should contain the property url. We suppose that the url contains the JSON data you want to pass.
Try the following 2 approaches:
// Approach 1:
func callJS() {
let json = "{ url:\"An url with json?\"}"
let scriptString = "let result=\(json); appQrHandlerSet(result);"
webView?.evaluateJavaScript(scriptString, completionHandler: { (object, error) in
})
}
// Approach 2:
func initWebViewWithJs() {
let config = WKWebViewConfiguration()
config.userContentController = WKUserContentController()
let json = "{ url:\"An url with json?\"}"
let scriptString = "let result=\(json); appQrHandlerSet(result);"
let script = WKUserScript(source: scriptString, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true)
config.userContentController.addUserScript(script)
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: 320, height: 400), configuration: config)
}
Related
For some reason that I don't understand, the Action Extension Button (in Share menu) doesn't respond. Action extension, at this point, catches the URL from Safari (where it was launched from) to make some things after. As a layer between Web and extension there is JS file (maybe something wrong here, i just copied it)
ViewController:
class ActionViewController: UIViewController {
var SafariURL: NSURL!
override func viewDidLoad() {
super.viewDidLoad()
let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem
let itemProvider = extensionItem!.attachments?.first as? NSItemProvider
let propertyList = String(kUTTypePropertyList)
if itemProvider!.hasItemConformingToTypeIdentifier(propertyList) {
print("I'm here2")
itemProvider!.loadItem(forTypeIdentifier: propertyList, options: nil, completionHandler: { (item, error) -> Void in
let dictionary = item as? NSDictionary
OperationQueue.main.addOperation {
let results = dictionary![NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary
let urlString = results!["currentUrl"] as? String
self.SafariURL = NSURL(string: urlString!)
}
})
} else {
print("error")
}
}
#IBAction func done() {
// Return any edited content to the host app.
// This template doesn't do anything, so we just echo the passed in items.
self.extensionContext!.completeRequest(returningItems: self.extensionContext!.inputItems, completionHandler: nil)
}
JS File:
var GetURL = function() {};
GetURL.prototype = {
run: function(arguments) {
arguments.completionFunction({ "currentUrl" : document.URL });
},
finalize: function(arguments) {
var message = arguments["statusMessage"];
if (message) {
alert(message);
}
}
};
var ExtensionPreprocessingJS = new GetURL;
Finally, you should change a content of override func viewDidLoad to
super.viewDidLoad()
if let inputItem = extensionContext?.inputItems.first as? NSExtensionItem {
if let itemProvider = inputItem.attachments?.first {
itemProvider.loadItem(forTypeIdentifier: kUTTypePropertyList as String) { [self] (dict, error) in
guard let itemDictionary = dict as? NSDictionary else { return }
guard let javaScriptValues = itemDictionary[NSExtensionJavaScriptPreprocessingResultsKey] as? NSDictionary else { return }
self.Pageurl = javaScriptValues["URL"] as? String ?? ""
JS is ok!
I do the demo base on this tutorial: https://github.com/valor-software/ng2-file-upload. I want to single file upload but without remove file button. By adding the File A, after that I add the File B. File A will be replaced by file B. here is my uploader:
this.uploader = new FileUploader(
{
url: this.baseURL,
allowedFileType: ["xls"],
maxFileSize: 5,
queueLimit: 1
});
Please advice me
As Arun Muthiyarkath suggested, you can use the onAfterAddingFile, but the shorter code would be:
ngOnInit() {
this.uploader.onAfterAddingFile = (fileItem: FileItem) => {
if (this.uploader.queue.length > 1) {
this.uploader.removeFromQueue(this.uploader.queue[0]);
}
};
}
Source: https://github.com/valor-software/ng2-file-upload/issues/703
Probably you can use onAfterAddingFile callback of the library provided function. Below is the sample code. This is always override old file with latest file and queue will always contain one item which is the latest file.
ngOnInit() {
this.uploader.onAfterAddingFile = (fileItem: FileItem) => this.onAfterAddingFile(fileItem)
}
onAfterAddingFile(fileItem: FileItem) {
let latestFile = this.uploader.queue[this.uploader.queue.length-1]
this.uploader.queue = [];
this.uploader.queue.push(latestFile);
}
this.uploader.onAfterAddingFile = (fileItem: FileItem) => {
if (this.uploader.queue.length > 0) {
this.uploader.queue = [fileItem];
}
};
I'm following this tutorial online https://makeapppie.com/2016/06/28/how-to-use-uiimagepickercontroller-for-a-camera-and-photo-library-in-swift-3-0/ (with a little bit of a twist). I'm trying to call my UIImagePickerController from a webview and I'm not sure how to change the code to get it to work properly. The difference is that I'm going to be receiving a call from javascript and then invoking the picker as a result instead of with a UIButton. Then I want to send the image back as a base64 string using my javascript interface.
Here is what I have so far.
import UIKit
import WebKit
class ViewController: UIViewController,
WKScriptMessageHandler,
UIImagePickerControllerDelegate,
UINavigationControllerDelegate {
var webView: WKWebView?
let userContentController = WKUserContentController()
let picker = UIImagePickerController();
#IBAction func photoFromLibrary(_ sender: UIBarButtonItem) {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
present(picker, animated: true, completion: nil)
}
override func loadView() {
super.loadView()
let config = WKWebViewConfiguration()
config.userContentController = userContentController
self.webView = WKWebView(frame: self.view.bounds, configuration: config)
userContentController.add(self, name: "iOS")
let url = URL(string:"https://relate.lavishweb.com/account")
let request = URLRequest(url: url!)
_ = webView?.load(request)
self.view = self.webView
}
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
webView?.evaluateJavaScript("window.settings.setImageBase64FromiOS()") { (result, error) in
if error != nil {
print("Success")
} else {
print("Failure")
}
}
// now use the name and token as you see fit!
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : AnyObject])
{
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage //2
// myImageView.contentMode = .scaleAspectFit //3
// myImageView.image = chosenImage //4
//I want to do additional stuff here and send back as a base64 String
dismiss(animated:true, completion: nil) //5
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
}
Hi I have the same problem an ein solved it, but it's a little dirty.
In viewDidLoad() you override the Delegate from WKWebView. The WKWebView use the Delegate, too. You need to save the Delegate local.
var oldDelegate: UIImagePickerControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
oldDelegate = picker.delegate // save the Delegate from WKWebView
picker.delegate = self
}
now you you can run your code in your delegate. In the end of your method imagePickerController() you have to invoke imagePickerController() from the old delegate.
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : AnyObject]){
var myinfo = info
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage //2
// myImageView.contentMode = .scaleAspectFit //3
// myImageView.image = chosenImage //4
myinfo[UIImagePickerControllerOriginalImage] = chosenImage
myinfo[UIImagePickerControllerImageURL] = nil
oldDelegate?.imagePickerController!(picker, didFinishPickingMediaWithInfo: myinfo)
}
I set the URL nil, because the WKWebView load the image direct from drive if the URL is filled.
myinfo[UIImagePickerControllerImageURL] = nil
I hope this is helpful.
Okay I figured it out,
So I didn't know what IBAction was but basically that means that the function that I'm going to declare after it is something that is called by an Interface Builder Element such as a UIButton or something like that. After realizing this, I just changed the function to
func photoFromLibrary() {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
present(picker, animated: true, completion: nil)
}
then in my JavaScript interface I simply called the function when I received the call from JavasScript.
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
webView?.evaluateJavaScript("window.settings.setImageBase64FromiOS()") { (result, error) in
if error != nil {
print("failure")
} else {
self.photoFromLibrary()
}
}
}
Stay tuned and I will post how to encode an image to a Base64 string while also shrinking it at load time.(Once I find out how to do that ofcourse)
EDIT: I figured out how to resize the image and convert to Base64 string very quickly.
I implemented this extension...
extension UIImage {
func resized(withPercentage percentage: CGFloat) -> UIImage? {
let canvasSize = CGSize(width: size.width * percentage, height: size.height * percentage)
UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: canvasSize))
return UIGraphicsGetImageFromCurrentImageContext()
}
func resized(toWidth width: CGFloat) -> UIImage? {
let canvasSize = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: canvasSize))
return UIGraphicsGetImageFromCurrentImageContext()
}
}
and then I returned the string like so...
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : AnyObject])
{
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
let thumb = chosenImage.resized(toWidth: 72.0)
let imageData:NSData = UIImagePNGRepresentation(thumb!)! as NSData
let dataImage = imageData.base64EncodedString(options: .lineLength64Characters)
print(dataImage)
dismiss(animated:true, completion: nil) //5
}
I am trying to access a JSON object in a URL inside the UIWebView. Here is my code for that -
func webView(myWebView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
let requestUrl:NSURL = request.URL!
let url:String = requestUrl.absoluteString
if url.rangeOfString("token") != nil {
print("exists")
let index = url.rangeOfString("token=", options: .BackwardsSearch)?.endIndex
let tokenValue = url.substringFromIndex(index!)
if let data = tokenValue.dataUsingEncoding(NSUTF8StringEncoding) {
do {
let json: AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary
print(json)
} catch {
print("Something went wrong")
}
}
self.tokenField.text = "\(tokenValue)"
}
The 'request URL' is coming from the following JS -
var tokenObj = {"accessToken":"abc123"};
window.location.href = "didtap://LoginButton?token=" + tokenObj;
The problem here is when I am trying to access the JSON Object using Swift, I see the URL coming in as didtap://LoginButton?token=[object%20Object]
Here is also a screenshot of my debugger.
I am looking for the JSON object as is, so I can use the token back in my app where needed.
You can use substring.stringByRemovingPercentEncoding will solve your problem
As I have found out there is no way to change the device brightness using Phonegap, so I have decided to create this plugin by my self. I am new to Phonegap and I do not know is it hard or not.
I have red some examples on how to create plugins for Phonegap But there are some things I don't understand.
I have this code for changing the screen brightness and I want to create a method for Phonegap that calls it:
private void setBrightness(int brightness) {
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.screenBrightness = brightness / 100.0f;
getWindow().setAttributes(layoutParams);
}
is it possible?
Thanks
Yeah, it's pretty easy to do if you follow the plugin development guide. For what you want to do it would be like this:
cordova.define("cordova/plugin/brightness",
function(require, exports, module) {
var exec = require("cordova/exec");
var Brightness = function () {};
var BrightnessError = function(code, message) {
this.code = code || null;
this.message = message || '';
};
Brightness.CALL_FAILED = 0;
Brightness.prototype.set = function(level,success,fail) {
exec(success,fail,"Brightness", "set",[level]);
};
var brightness = new Brightness();
module.exports = brightness;
});
Then you'll need to write some Java code to do the phone call. You'll need to create a new class that extends the Plugin class and write an execute method like this:
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
try {
if (action.equals("set")) {
int brightness = args.getInt(0);
WindowManager.LayoutParams layoutParams = getWindow().getAttributes();
layoutParams.screenBrightness = brightness / 100.0f;
this.cordova.getActivity().getWindow().setAttributes(layoutParams);
}
else {
status = PluginResult.Status.INVALID_ACTION;
}
return new PluginResult(status, result);
} catch (JSONException e) {
return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
}
Whatever you call this class you'll need to add a line in the res/xml/config.xml file so the PluginManager can create it.
<plugin name="Brightness" value="org.apache.cordova.plugins.Brightness"/>
and finally in your JavaScript code you'll need to create they plugin and call it like this:
function panicButton() {
var brightness = cordova.require("cordova/plugin/brightness");
brightness.set(50);
}
That should about do it.