I am working on an app that is built using jQuery mobile and Phonegap. It has been working fine for over a year. Then a month or two ago, the controls (specifically map type, zoom, and street view) went missing without the app being updated, and only on iOS.
I have tried running the app through the phone's browser and it works fine. It is only after it has been compiled by phonegap (build) that the issue exists. I've attempted to manually force the UI settings to true, but only the map type control comes up. I have also tried modifying CSS to give the controls a crazy high z-index, and that made no difference either.
I have not been able to find any relevant information online. How can I get the controls to show up again?
In my case I had a missing street view icon. Google Maps iframe didn't trigger onload event because Cordova rejected empty url of iframe.
ERROR Internal navigation rejected - <allow-navigation> not set for url='about:blank'
I set <allow-navigation href="*" /> in config.xml
I've been in contact with Google, and it turns out a bug was introduced in version 3.32 that's causing this. They're working on it as far as I know, but came up with a workaround in the meantime.
First, you need to specify version 3.31 in the script tag:
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE&v=3.31"></script>
And then when creating the mapOptions, manually set the controls you want to true. In my case:
var mapOptions = {
center: latlng,
zoom: 16,
mapTypeControl: true,
streetViewControl: true,
zoomControl: true
};
For those who do not use Phonegap but native WKWebView and you by default disabled any scheme except "file"... you must also enable "about" scheme in webView() func in ViewController.swift
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void) {
var url = navigationAction.request.url;
let scheme = url!.scheme;
// open local scheme in WebView
if (scheme == "file") {
decisionHandler(.allow);
}
// needed to show google maps icons for controls like zoomControl and streetViewControl
else if (scheme == "about") {
decisionHandler(.allow);
}
// other schemes like fb/http/https/mailto open in external application
else {
UIApplication.shared.openURL(url!);
decisionHandler(.cancel);
}
}
Related
Seems like android's WebViewClient has methods like: onProgressChanged()
Anything for ios' wkwebview? (or any other iOS webview)
Webview's onNavigationStateChangedoesn't seem to help here.
Would like to evaluate JS on www.example.com & then onwww.example.com/about.
What exactly do you mean with onNavigationStateChange? This doesn't sound familiar to me.
You should implement WKNavigationDelegate. [https://developer.apple.com/documentation/webkit/wknavigationdelegate].
If you want to load JS after loading an url, you can implement webView(_, didFinish: WKNavigation). WKNavigation offers the api to check request / url.
To load some JS before navigation finished, you can try with webView(WKWebView, decidePolicyFor: WKNavigationAction) [https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455641-webview]
or webView(WKWebView, decidePolicyFor: WKNavigationResponse) [https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455643-webview].
See WKUserScript, which is designed specifically for this purpose. When creating the WKWebView, you'll add a WKUserContentController, which can add scripts using addUserScript.
I am create a iOS Application. I am using WKWebView at some stage to show some files of any extension types. For Audio, Video, html, text, pdf, documents files its working well. But files like .zip , .csv and many others its not showing proper data or show blank screen without any error I am getting in its navigations delegates methods.
My Question is how can I check if my WKWebView is able to load/support that file? So that if it's not able to load or support that file, I can show another view where I will direct download that file to File manager and give user option to save or share that file.
Like In Safari browser when I am trying to load zip file its not show any preview , its show an alert to download (in iOS 13) or show Save and share file action (in iOS 13). How Safari is detecting that its support that file or not?
Please do not suggest to use direct String matching for mime types or extensions because there can be 1000+ files extensions in the world.
You need to make your controller as webView.navigationDelegate and define the navigation response delegate callback as follows:
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse,
decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void) {
if navigationResponse.canShowMIMEType {
decisionHandler(.allow)
} else {
decisionHandler(.cancel)
// do something else with `navigationResponse.response`
}
}
I have tried every possible way to access camera on webview on cordova.
It work on android, but doesn't work on iOS.
Can someone explain how to implement access camera feature via cordova webview on iOS thanks.
Inappbrowser side (Angular)
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices
.getUserMedia({ video: { facingMode: 'environment' } })
.then(stream => {
// this.videoDom.srcObject = stream;
this.videoDom.srcObject = stream;
this.videoDom.setAttribute('playsinline', 'true');
this.videoDom.play();
this.stream = stream.getTracks();
requestAnimationFrame(tick);
})
}
Cordova side
I have install cordova-plugin-camera and add permission in config.xml on ios platform.
On iOS11/12 navigator.getMediaDevices is not available for WKWebView and UIWebView. It is only available for Safari. (https://forums.developer.apple.com/thread/88052)
WebRTC is only supported in Safari. No WKWebView, not even
SFSafariViewController.
You can try to use this plugin normally should solve your problem: https://github.com/phonegap/phonegap-plugin-media-stream
navigator.mediaDevices.getUserMedia({
'audio': true,
'video': {
facingMode: 'environment'
}
}).then(function(mediaStream) {
// Do what you want with
}
There is a simpler way, just use input type file
This shows the camera for taking a picture
<input type="file" accept="image/*" capture>
This for recording video
<input type="file" accept="video/*" capture>
This will prompt to take a picture or video, choose from the photo library or explore files
<input type="file">
There are a few other combinations. But it probably doesn't work on Android
This is a duplicate of: NotReadableError: Could not start source (Please read this link as its related to Cordova and getUserMedia) and potentially Progressive Web App: Error Accessing navigator.mediaDevices.getUserMedia?
There are changes to Safari on iOS 13 & Safari 13: https://developer.apple.com/documentation/safari_release_notes/safari_13_release_notes
SFSafariViewController has gained getUserMedia functionality (!!!)
https://bugs.webkit.org/show_bug.cgi?id=183201
However WKWebView does not seem to gain getUserMedia functionality (this might be a bug, watch the webkit link closely):
https://bugs.chromium.org/p/chromium/issues/detail?id=752458
https://bugs.webkit.org/show_bug.cgi?id=185448
iOS 13 and Safari 13 release notes:
https://developer.apple.com/documentation/ios_ipados_release_notes/ios_13_release_notes
https://developer.apple.com/documentation/safari_release_notes/safari_13_release_notes
I've thought of a hacky way you can make this work on iOS by using the new postMessage API feature of cordova-plugin-inappbrowser which enables you to send messages from pages loaded into the Inappbrowser Webview back to the main Cordova app Webview.
This is not present in the latest release on npm (3.0.0), so you'd need to install the master version (3.1.0-dev) directly from Github:
cordova plugin add https://github.com/apache/cordova-plugin-inappbrowser
In the page loaded into the inappbrowser, you can then post messages back to the Cordova app webview:
function openCamera(){
postMessage({
action: "camera"
});
}
function postMessage(message){
if(!webkit.messageHandlers.cordova_iab) throw "Cordova IAB postMessage API not found!";
webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify(message));
}
<button onclick="openCamera()">Open camera<button>
On the Cordova app side, you can then listen for that message and respond to it:
var iab = cordova.InAppBrowser.open(myUrl, '_blank', iabOpts);
iab.addEventListener('message', function (e) {
if(e.data.action === 'camera'){
openCamera();
}
});
function openCamera() {
var animationDelay = 500; // delay to wait for camera window animation
navigator.camera.getPicture(function(){
log("successfully opened camera");
if (device.platform === "iOS"){
// unhide IAB
iab.show();
}
}, function(cameraError){
error("error opening camera: "+cameraError);
if (device.platform === "iOS"){
iab.show();
}
});
if (device.platform === "iOS"){
// hide IAB so camera window is in view
setTimeout(iab.hide, animationDelay);
}
}
This allows you to directly call cordova-plugin-camera from within the inappbrowser.
However it is hacky because on iOS, by default the camera window will appear below the inappbrowser window in the view hierarchy and hence not be visible.
My hack is to hide the inappbrowser window upon opening the camera, which causes the camera window to be at the top of the visible view hierarcy and be displayed.
However, upon dismissing the camera window, the Cordova app window will briefly be displayed while the inappbrowser window is being animated to show again.
I created a test case example in my inappbrowser test app repo: https://github.com/dpa99c/cordova-plugin-inappbrowser-test/tree/camera
You can try it like this:
git clone -b camera https://github.com/dpa99c/cordova-plugin-inappbrowser-test
cd cordova-plugin-inappbrowser-test
cordova platform add ios
cordova run ios
I created a simple iOS app, which opens a URL with WKWebView. On the website, there is a link to a PDF Document. When I open the site on my browser, I can click onto the Link, and the PDF document opens. But on my App, nothing happens when I click onto the link.
How can I fix it? Do I have to put something into my info.plist?
SWIFT 3.* & 4.* *
First you have to download that pdf file into your app, after downloading you have to get that file path, then that file path should be use like following way in WKWebView.
let fileURL = URL(fileURLWithPath: filePathURLData as! String)
//print(fileURL)
webView.loadFileURL(fileURL, allowingReadAccessTo: fileURL)
Here filePathURLData is your actual file path which you have downloaded into your app, you have to convert this into URL, then you need to load that file into WKWebView
Thanks
Hope this will help you.
This will show any file in the WKWebView (doc, docx, xlsx, pdf, google doc, pages & Any textfile)
Likely, you are using target="_blank" in your anchor tag. That opens up a new window to display the link. WKWebView is blocking your attempt to open a new window (at least by default).
The code below still does not create a new window, but instead opens the PDF, etc link in the current WKWebView.
The other option seems to be to create a new WKWebView and return it, so the ios and open the link in that, but I don't want extra Views being created by every click on a website inside the WKWebView.
In your ViewController.viewDidLoad
webView.uiDelegate = self
Then add the extension for the delegate
extension ViewController: WKUIDelegate {
/**
* Force all popup windows to remain in the current WKWebView.
* By default, WKWebView is blocking new windows from being created
* ex text.
* This code catches those popup windows and displays them in the current WKWebView.
*/
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
// open in current view
webView.load(navigationAction.request)
// don't return a new view to build a popup into (the default behavior).
return nil;
}
}
I have same issue, and found out the pdf file is using unsecured http. Therefore the app refuse to open it.
Try to check with https link and see if it works.
Also with WKWebView, you don't need to download the pdf file before open it. Just load the url directly, i.e
webView.load(URLRequest(url: URL(string: "https-pdf-link")!))
Objective C:
NSURL *fileUrl = [[NSURL alloc] initWithString:filePathURLData];
[webView loadFileURL:fileUrl allowingReadAccessToURL:fileUrl];
Another way to open PDF saved in document directory:
NSData *data = [NSData dataWithContentsOfFile:fileURL];
[webView loadData:data MIMEType:#"application/pdf" characterEncodingName:#"" baseURL:[NSURL URLWithString:fileURL]];
I'm very new to fine-uploader; I hope my question is relevant...
I'm trying to disable the camera for users of our Web App on iPad and iPhone only (iOS), both for Safari and Chrome. I have tried setting the option camera: {ios: false} but the camera option still shows in Safari and Chrome. When I use workarounds: { ios8BrowserCrash: true}, the camera option does disappear in Chrome but still shows in Safari. What am I missing?
We are using fine-uploader 5.1.2, I briefly tried 5.2.2 with the same results. The app is HTML5, Javascript, Angular with Java back-end. I have tested on iPad with iOS 8.3, 8.4 and 9 beta.
As an aside, the reason I'm trying to disable the camera is due to iOS often crashing when loading the image from the camera. I have found the application crashing a lot less when loading from the device image library, bypassing the camera. Is that a known issue with iPad/iPhones?
Thanks in advance for the help.
Thanks #Ray. For reference, I'm now using the latest FineUploader version 5.3.0.
As you suggested the multiple attribute was being removed. I traced it to the input.removeAttribute("multiple"); code below (s3.fine-uploader.js):
setMultiple: function(isMultiple, optInput) {
var input = optInput || this.getInput();
// Temporary workaround for bug in in iOS8 UIWebView that causes the browser to crash
// before the file chooser appears if the file input doesn't contain a multiple attribute.
// See #1283.
if (options.ios8BrowserCrashWorkaround && qq.ios8() && (qq.iosChrome() || qq.iosSafariWebView())) {
input.setAttribute("multiple", "");
}
else {
if (isMultiple) {
input.setAttribute("multiple", "");
}
else {
input.removeAttribute("multiple");
}
}
},
Despite options.ios8BrowserCrashWorkaround being set to true in my code (ios8BrowserCrash: true), the program was still going through to removeAttribute("multiple") line of code when running on IPad/Safari.
After several tries and errors I found out that (possibly...) the library code was missing testing for the condition qq.iosSafari()on an iPad (iOS 8.3) ; the qq.iosSafariWebView() test isn't sufficient to detect the Safari browser on my iPad, therefore missing the code where the multiple attribute is set.
I found out that the following options values in my calling code fixed the issue.
function initialiseS3() {
uploader = new qq.s3.FineUploader({
element: $element[0],
template: $(contents)[0],
debug: false,
// iosEmptyVideos workaround must be false to enable FineUploader to keep multiple:true in iOS
workarounds: {
iosEmptyVideos: false,
ios8BrowserCrash: true
},
// Must add the test qq.iosSafari() to set multiple to true and have the camera turned off on iPad
multiple: qq.ios8() && (qq.iosSafari() || qq.iosChrome() || qq.iosSafariWebView()) ? true : false,
camera: {
ios: false
},
… (more initialisations)
`
The last catch was to override the default value for the workaround option iosEmptyVideos and set it to iosEmptyVideos: false to avoid the library forcing multiple to false again. I hope this makes sense…