How to access camera on iOS11 home screen web app? - javascript

Summary
We cannot access camera from an iOS11 (public release) home screen web app using either WebRTC or the file input, details below. How can our users continue to access the camera please?
We are serving the web app page over https.
Update, April
The public release of iOS 11.3 seems to have fixed the issue and file input camera access is working again!
Update, March
As people here have said the Apple docs advise web app camera function is returning in 11.3 along with service workers. This is good but we are not sure yet if we want to everyone to to reinstall again until we can thoroughly test on 11.3GM.
Solution, November
We lost hope Apple want to fix this and moved forward. Modified our web app to remove the iOS "Add to home screen" function and asked affected users to remove any previous home screen icon.
Update, 6 December
iOS 11.2 and iOS 11.1.2 don't fix.
Workarounds, 21 September
Seems we could ask existing customers of the web app
not upgrade to iOS11 - good luck with that :)
take photos in iOS camera and then select them back in the web app
wait for next ios beta
reinstall as a Safari in-browser page (after we remove ATHS logic)
switch to Android
File Input
Our current production code uses a file input which has worked fine for years with iOS 10 and older. On iOS11 it works as a Safari tab but not from the home screen app. In the latter case the camera is opened and only a black screen is shown, hence it is unusable.
<meta name="apple-mobile-web-app-capable" content="yes">
...
<input type="file" accept="image/*">
WebRTC
Safari 11 on iOS11 offers WebRTC media capture which is great.
We can capture a camera image to canvas on a normal web page on desktop and mobile using navigator.mediaDevices.getUserMedia per the sample code linked here.
When we add the page to iPad or iPhone home screen, navigator.mediaDevices becomes undefined and unusable.
<meta name="apple-mobile-web-app-capable" content="yes">
...
// for some reason safari on mac can debug ios safari page but not ios home screen web apps
var d = 'typeof navigator : ' + typeof navigator; //object
d += 'typeof navigator.mediaDevices : ' + typeof navigator.mediaDevices; // undefined
// try alternates
d += 'typeof navigator.getUserMedia : ' + typeof navigator.getUserMedia; // undefined
d += 'typeof navigator.webkitGetUserMedia : ' + typeof navigator.webkitGetUserMedia; // undefined
status1.innerHTML = d;

We have quite similar problem. So far the only workaround we were able to do is to remove the meta tag for it to be "apple-mobile-web-app-capable" and let users to open it in Safari, where everything seems to work normally.

Update: While some earlier published changelogs and postings led me to believe that Web Apps using a manifest.json instead of apple-mobile-web-app-capable would finally have access to a proper WebRTC implementation, unfortunately this is not true, as others here have pointed out and testing has confirmed. Sad face.
Sorry for the inconveniences caused by this and let's hope that one lucky day in a galaxy far, far away Apple will finally give us camera access in views powered by (non-Safari) WebKit...
Yes, as others have mentioned, getUserMedia is only available directly in Safari but neither in a UIWebView nor WKWebView, so unfortunately your only choices are
removing <meta name="apple-mobile-web-app-capable" content="yes"> so your 'app' runs in a normal Safari tab, where getuserMedia is accessible
using a framework like Apache Cordova that grants you access to a device's camera in other ways.
Here's to hoping Apple removes this WebRTC restriction rather sooner than later...
Source:
For developers that use WebKit in their apps, RTCPeerConnection and RTCDataChannel are available in any web view, but access to the camera and microphone is currently limited to Safari.

Good news! The camera finally seems to be accessible from a home screen web app in the first iOS 11.3 beta.
I have made a repo with a few files, which demonstrate that it works:
https://github.com/joachimboggild/uploadtest
Steps to test:
Serve these files from a website accessible from your phone
Open the index.html in iOS Safari
Add to home screen
Open app from home screen. Now the web page is open in full screen, without navigation ui.
Press the file button to select an image from camera.
Now the camera should work normally and not be a black screen. This demonstrates that the functionality works again.
I must add that I use a plain field, not getUserMedia or somesuch. I do not know if that works.

Apparently is solved in "ios 13 beta 1":
https://twitter.com/ChromiumDev/status/1136541745158791168?s=09
Update 20/03/2020: https://twitter.com/firt/status/1241163092207243273?s=19

This seems to be working again in iOS 11.4 if you are using a file input field.

Recently I faced the same problem, the only solution I came up with was to open in the app in browser instead of the normal mode. But only on iOS!
The trick was to create 2 manifest.json files with different configurations.
The normal one for android and one for everything is Apple, manifest-ios.json, the only difference will be on the display property.
Step 1: Add id to the manifest link tag:
<link id="manifest" rel="manifest" href="manifest.json">
Step 2: Added this script to the bottom of the body:
<script>
let isIOS = /(ipad|iphone|ipod|mac)/g.test(navigator.userAgent.toLowerCase());
let manifest = document.getElementById("manifest");
if (isIOS)
manifest.href = 'manifest-ios.json'
</script>
Step 3: in the manifest-ios.json set the display to browser
{
"name": "APP",
"short_name": "app",
"theme_color": "#0F0",
"display": "browser", // <---- use this instead of standard
...
}
Another problem appears such as opening the app multiple times in multple tabs, sometimes.
But hope it helps you guys!

Related

NotReadableError: Could not start source

I have added this piece of code in my project
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia = (
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia
);
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
Then I'm trying to access a video stream using getUserMedia
navigator.mediaDevices.getUserMedia({
video: true,
audio: false
}).then(stream => {
// do stuff
}).catch(error => {
console.log(error.name + " " + error.message);
});
When I test this in my emulators it works on android versions 5 and up, however when I run it on an actual device I get this error
NotReadableError Could not start source
I have added the cordova-plugin-media-capture plugin to make sure my app will request the appropriate permissions, however I don't want to use the plugin I'd rather use the getUserMedia API.
So far my researches show that the reason for this error is that some other app is already using the camera but that's not the case, I even went a step further and restarted the device, then opened my app, making sure there are no other running apps and I still got the error.
Has anyone had this issue?
Update - 19/11/2020
WKWebView can use getUserMedia in iOS 14.3 beta 1.
https://bugs.webkit.org/show_bug.cgi?id=208667
https://bugs.chromium.org/p/chromium/issues/detail?id=752458
Update - 04/06/2020
Another bug ticket has been filed specifically for WKWebView. No support.
https://bugs.webkit.org/show_bug.cgi?id=208667
Updates to standalone mode gaining getUserMedia access in iOS 13.4
https://bugs.webkit.org/show_bug.cgi?id=185448#c6
Update - 14/09/2019
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 (!!!, however I need to confirm this, please see below for reports of it working)
https://bugs.webkit.org/show_bug.cgi?id=183201
However WKWebView does not seem to gain getUserMedia functionality:
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
Update - 04/11/2018 - Links to working Ionic, Cordova and Native android examples with instructions
GitHub link to working Cordova example
GitHub link to working Android example
GitHub link to a working Ionic example
Steps to achieve getUserMedia access on Android via the Cordova framework are:
Follow Cordova Android install instructions (link)
Add Permissions to AndroidManifiest.xml (link)
Save WebRTC Adapter.js file to ./www/js/adapter.js and include in ./www/index.html
Add cordova plugin add cordova-plugin-android-permissions
Add plugin permission code, and the necessary getUserMedia code inside of the ./www/js/index.js file. Make sure you use getUserMedia adapter. Please see this file as an example (link).
Please see the full line by line instructions with a success and error image inside the GitHub project.
I am not sure how much of this relates to Cordova... However I had this error when I made my own Android getUserMedia test app (link). It is dependant mainly on the native app user permissions, then how the parent app creates the webviews, which version of webrtc is packaged within your app, and how you call getUserMedia.
JavaScript side of the application:
Rather than doing browser shim code yourself make sure you use the WebRTC adapter (link). This removes a lot of common problems. You can see an example here (link). I also recommend looking at the WebRTC Samples here (link).
Native side of the application:
You will need Mic and Camera user permissions for Video and Audio. This is the main culprit. You need to make sure they have been accepted before the creation of the WebView. Thus all permission checking, popups, etc, need to happen before the creation of the WebView. If permissions are granted after you most likely need to reboot the App, etc.
When you build and deploy your application go to App Settings and manually turn on the permissions if you haven't been prompted already. Then it should work.
I wasn't able to get Video/Audio emulation working in the emulator only on the actual device. I also only encountered the NotReadableError on Android utilising a WebChromeView before permissions have been accepted. Lastly The min API version for Android is 21 (Lollipop) for this functionality as the parent application needs to allow run-time permissions via WebView onPermissionRequest (link).
As numerous in-app browsers (Facebook, Pinterest, etc) do not handle onPermissionRequest on Android WebRTC via a website typically doesn't work. On iOS it is guaranteed (as of April 2018) not to work as Apple have only allowed WebRTC access through the Safari only. Thus Cordova is limited to Android API 21 if it handles the permissions correctly.
I wanted to add the solution to my saga of fighting this particular error. I am using Ionic to build a WebRTC chat app, and have got this error with my native Android build. Here are the things that made all the difference.
Install Ionic's AndroidPermissions plugin...
$ ionic cordova plugin add cordova-plugin-android-permissions
$ npm install --save #ionic-native/android-permissions
Don't forget to add it to app.module.ts as a provider
In your component's .ts file...
import { AndroidPermissions } from '#ionic-native/android-permissions';
...
iosCordova = false; // I use these for easy if-else logic later
androidCordova = false; // but I want you to see how I handle the logic
constructor(private platform:Platform, private androidPermissions: AndroidPermissions, etc...) {
navigator.getUserMedia = ((<any>navigator).getUserMedia || (<any>navigator).webkitGetUserMedia || (<any>navigator).mozGetUserMedia || (<any>navigator).msGetUserMedia);
this.iosCordova = this.platform.is('ios') && typeof cordova !== 'undefined';
this.androidCordova = this.platform.is('android') && typeof cordova !== 'undefined';
platform.ready().then(() => {
if( this.androidCordova ){ // is Android Native App
// alert("Android Native")
androidPermissions.requestPermissions(
[
androidPermissions.PERMISSION.CAMERA,
androidPermissions.PERMISSION.MODIFY_AUDIO_SETTINGS,
androidPermissions.PERMISSION.RECORD_AUDIO
]
).then(()=>{
//getDevices uses Enumerate Devices and initWebRTC starts the chat connections, etc...
this.getDevices().then(() => this.initWebRTC())
})
}
})
}
ngOnInit() {
if( !this.androidCordova ){ // is NOT Android Native App
// alert("NOT Android Native")
try {
this.getDevices().then(() => this.initWebRTC())
} catch(e) {
alert(e);
}
}
}
...
Inspect your config.xml at myAppName/config.xml and add xmlns:android="http://schemas.android.com/apk/res/android" to your widget tag and add the permissions request. I had issues trying to include them in the previously existing tags, and just add these permissions requests right under the closing tags (creating my own second set)
<widget id="your.app" version="1.2.3" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0">
...
</platform> // previously existing platform name="android" closing tag
<platform name="android">
<custom-config-file parent="/manifest" target="AndroidManifest.xml">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</custom-config-file>
</platform>
<platform name="ios"> // previously existing platform name="ios" opening tag
Now, you need to inspect your AndroidManifest.xml file at myAppName/platforms/android/app/src/main/AndroidManifest.xml and look for these permissions. If they are not there, add them
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Having these permissions declared in the manifest is critical to not being ignored. Apparently Android 26 is getting strict on permissions, and you can't just ask willy-nilly for them. According to the documentation I've been reading, if you are not actually using the permission from within the code you are calling it from, your request will be dropped by the OS and the user will never see it.
Anyway, I'm very junior to all this Ionic and native device development, so if anyone has anything enlightening to add, please do so! Thanks everyone!

NotReadableError: Failed to allocate videosource

I get this error in Firefox 51 when I try to execute the following code and when I select my laptop's camera:
navigator.getMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mediaDevices.getUserMedia ||
navigator.msGetUserMedia);
navigator.getMedia({
video: true,
audio: false
},
function(stream) {
if (navigator.mozGetUserMedia) {
video.mozSrcObject = stream;
} else {
var vendorURL = window.URL || window.webkitURL;
video.src = vendorURL.createObjectURL(stream);
}
video.play();
},
function(err) {
console.log("An error occured! " + err);
}
);
Error:
NotReadableError: Failed to allocate videosource
Can someone elaborate what this means? Is my webcam broken? I used it from the script just yesterday without problems. It's not allocated to other application.
NotReadableError is the spec compliant error thrown by Firefox when webcam access is allowed but not possible.
Most commonly this happens on Windows because the webcam is already in use by another app. Firefox will throw this error on both Windows and Mac even though only on Windows processes get exclusive access to the webcam.
The error can happen for other reasons:
Although the user granted permission to use the matching devices, a hardware error occurred at the operating system, browser, or Web page level which prevented access to the device.
Chrome throws TrackStartError instead. It also throws it for other reasons. Chrome tabs can share the same device.
Source: common getUserMedia() errors .
Please make sure your camera is not been used by some other application (chrome, ie or any other browser).
I wasted half my day searching for a solution, and in the end, found out my camera was used by other application.
I've encountered same issue on Windows 10, no other apps using my video device. The problem was that in Windows 10 in Settings->App permissions (in left column) there is a setting for microphone and camera (Allow apps to access your mic/camera) which needs to be turned on. It does not matter that you don't find your browser in app list below this setting, just enable it here and voila.
The message getUserMedia() error: NotReadableError was displayed for Chromium but not Firefox web browser. I also noticed that WebRTC examples using getUserMedia function without microphone access worked correctly in Chromium.
In fact, I had to make sure my microphone is enabled and select the correct microphone in Chromium / Chrome settings. Then WebRTC with audio and video access worked correctly.
If it is not a microphone problem, it may also be a webcam problem so you have to make sure your webcam is enabled and selected correctly in Chromium / Chrome settings.
Note that only one app at a time can use the webcam / microphone.
If you are here after or in December 2019 i would like to tell you few things
This feature navigator.getUserMedia() is deprecated.
Successor of this feature in the browsers will be window.navigator.mediaDevices.getUserMedia.
The new feature may not support in many browsers, since its still in the experiment mode few days ago chrome released its chrome 79 and its still not supporting in chrome 79 for me, and other than chrome and IE its working in all the browsers for me
Here is a quick code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Jello</title>
<style>
video{
width: 30%;
height: auto;
}
</style>
</head>
<body>
<video autoplay controls></video>
<button>Open Cam</button>
<script>
function getCam(){
window.navigator.mediaDevices.getUserMedia({video:true}).then((stream)=>{
// let videoTrack = stream.getVideoTracks()[0];
// console.log(videoTrack);
document.querySelector("video").srcObject = stream;
}).catch(err=> console.log(err.name))
}
// getCam();
document.querySelector("button").addEventListener("click", getCam);
</script>
</body>
</html>
Edit => if you are using in windows 10 make sure give chrome access your microphone and camera, otherwise it won't work
There is another solution to this problem. I had it with camera not working in Firefox and Skype, but working with the Camera app.
The solution was to give access to camera for "classical apps" (I do not know how it's called in English). It is in the same place access can be given or taken for all other apps, just bellow them make sure the classical apps are allowed as well. And not just giving for the app in question, like Firefox, all classical apps need to have that enabled
Tl;dr; - Check device drivers for any "funny" camera drivers
I just spent an hour on a call with a user who kept hitting this error, no matter what we tried and that includes go down every answer to this question. And we found another cause which I will now add here for the next poor soul to stumble on this.
In his case, he had installed an app called ChromaCam (which I exited almost as a first diag step) and this app installs a device driver called "Personify Virtual Camera Universal" Web search for that driver name will show a whole bunch of people having camera problems and the solution seems to be somewhat universal: uninstall the device driver. He didn't even know what ChromaCam was or why it was on his laptop, so we removed it, uninstalled the driver and everything started working perfectly!
There was another person in a different thread who had similar problem and for him it was some custom HP (?? - I think that's what he said) camera driver instead of normal generic one that Windows would have chosen.
Can someone elaborate what this means? Is my webcam broken? I used it
from the script just yesterday without problems. It's not allocated to
other application.
I've encountered exactly the same issue!
Shame on me! Because, in the meantime I'd added a beforeunload event, including the event.preventDefault as reported in the example.
After removing this event.preventDefault, everything worked fine - as expected.
I have searched everywhere for the solution at last found this. Basically in my case camera permission was turned on and Mozilla firefox can access web cam but chrome can't. Infact older versions of chrome like 74.x can use webcam but latest 84.x cannot. I thought the problem is with chrome but at last, I tried turning on my microphone access from windows 10 settings. Now chrome can access webcam too.
Solution: Please check you camera and microphone access both are turned on from windows settings.
The NonReadableError: Could not start video source is also thrown during a session (not local only!) if the camera change happens too quickly.
I don't know the solution yet, but I will edit my post accordingly once I got it.

Sending Data from a UIWebView back to an iOS Application with a custom URL Scheme breaks with Xcode 8/iOS 10

On iOS versions previous to 10, I was able to send information from the JavaScript/HTML loaded into a UIWebView back to my application by creating an iFrame on the document or setting document.location.href to a custom URL which the web view would tried to load:
<html>
<body><input id="clickMe" type="button" value="clickme" onclick="changeWindow();" /></body>
<script type="text/javascript">
function changeWindow() {
//create temp frame
iFrame = this.createIFrame('onStatusChange://eyJ1c2VyTmFtZSI6IkpBTCIsLCJwcm92aWRlciI6IkVtYWlsIn0=');
//remove the frame now
iFrame.parentNode.removeChild(iFrame);
}
function createIFrame(src) {
var rootElm = document.documentElement;
var newFrameElm = document.createElement('IFRAME');
newFrameElm.setAttribute('src', src);
rootElm.appendChild(newFrameElm);
return newFrameElm;
}
</script>
</html>
Then on the client, I would just listen for the UIWebViewDelegate callback webView:shouldStartLoadWithRequest:navigationType:, and check to see if the request.URL.scheme was equal to my custom scheme (in this case onStatusChange).
This is a popular way of communicating between the JavaScript and an iOS app, as seen in popular questions such as How to invoke Objective C method from Javascript and send back data to Javascript in iOS?.
This works on any app built with Xcode 7 (Objective-C or Swift) on iOS 9 and 10 devices. I'm running into an issue where the delegate method is not called on any applications built with Xcode 8. It's as if the web view isn't even trying to load the URL, which in turn is not triggering the delegate callback.
Were there any changes to UIWebView or WebKit from Xcode 7 to 8 or iOS 9 to 10 which would cause this not to work? What's really puzzling to me is that a production app I have built with Objective-C in Xcode 7 targeting iOS 8 works on an iOS 10 device, but a debug build built with Xcode 8 of the exact same codebase does not work.
Ok, long story short we use a special URL scheme onStatusChange:// to send Base64 encoded data from the web view back to our iOS application. I believe UIWebView on iOS 10 chokes when trying to load a URL that ends in one or more equals sign characters, and loads about:blank instead of the actual URL.
Since this works perfectly on iOS 9, I'm assuming this is a defect with iOS 10 and have opened rdar://29035522. A full reproducible example of the issue is available in the body of that radar.
I am reading through the Base-N encoding RFC to determine if it is acceptable to remove the padding = characters at the end of my data string, or if they need to be removed from the web and added on the client before decoding the data.
The solution I ended up implementing was percent-escaping the Base64 encoded data, and unescaping it on the client. Not the most elegant solution, but probably the best for safety.
Thats because iOS now blocks http requests by default. You have to reenable it in your info.plist.
https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33

Deeplinking mobile browsers to native app - Issues with Chrome when app isn't installed

I have a webpage, lets call it entry.html.
When a user enters this page, a javascript code (see below) is attempting to deep-link the user to the native iOS / Android app.
If the deep-link fails (probably if the app isn't installed on device), user should "fall back" to another page- lets call it fallback.html.
here is the javascript code that is running on entry.html:
$(function(){
window.location = 'myapp://';
setTimeout(function(){
window.location = 'fallback.html';
}, 500);
});
this is a standard deep-linking method that is recommended all over the network; try to deep-link, and if the timeout fires it means that deep-link didn't occur- so fallback.
this works fine, as long app is installed on device.
but if the app isn't installed, this is the behaviour when trying to deep-link:
Mobile Safari: I see an alert message saying "Safari cannot open this page..." for a moment, and then it falls-back properly to fallback.html- which is the expected behaviour.
Mobile Chrome is my problem.
when the app isn't installed, browser is actually redirected to the myapp:// url, which is of course, invalid- so i get a "not found" page, and fall-back doesn't occur.
Finally- my question is:
How can I fix my code so FALL-BACK WILL OCCUR on mobile Chrome as well? just like mobile Safari?
note: i see that LinkedIn mobile website does this properly, with Safari & Chrome, with or without the app installed, but i couldn't trace the code responsible for it :(
note2: i tried appending an iframe instead of window.location = url, this works only on Safari, mobile Chrome doesn't deep-link when appending an iFrame even if app is installed.
Thanks all!
UPDATE:
i found a decent solution, and answered my own question. see accepted answer for my solution.
for whoever is interested, i managed to find a decent solution to solve these issues with deeplinking Chrome on Android.
i abandoned the myapp:// approach, i left it functioning only in cases of an iOS device.
for Android devices, i'm now using intents which are conceptually different than the myapp:// protocol.
I'm mainly a web developer, not an Android developer, so it took me some time to understand the concept, but it's quite simple. i'll try to explain and demonstrate MY solution here (note that there are other approaches that could be implemented with intents, but this one worked for me perfectly).
here is the relevant part in the Android app manifest, registering the intent rules (note the android:scheme="http" - we'll talk about it shortly):
<receiver android:name=".DeepLinkReceiver">
<intent-filter >
<data android:scheme="http" android:host="www.myapp.com" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
now, after this is declared in the app manifest, i'm sending myself an email with "http://www.myapp.com" in the message.
when link is tapped with the Android device, a "chooser" dialog comes up, asking with which application i want to open the following? [chrome, myapp]
the reason this dialog came up upon tapping on a "regular" url, is because we registered the intent with the http scheme.
with this approach, the deeplink isn't even handled in the webpage, it's handled by the device itself, when tapping a matching link to an existing intent rule defined in the Android app manifest.
and yes, as i said, this approach is different by concept than the iOS approach, which invokes the deeplink from within the webpage, but it solves the problem, and it does the magic.
Note: when app isn't installed, no chooser dialog will come up, you'll just get navigated to the actual web page with the given address (unless you have more than 1 browser, so you'll need to choose one... but lets not be petty).
i really hope that this could help someone who's facing the same thing.. wish i had such an explanation ;-)
cheers.
It is very important to make sure that when you try to open a deeplink URL with JavaScript that the URL is properly formatted for the device and browser. (If you do not use the appropriate deeplink URL for the browser/platform, a user may be redirected to a “Page Not Found”, which is what you experience.)
Now you must note that Chrome on Android has a different URL format than the old standard Android browser 1! You need to annotate the deep links using href="android-app://" in the HTML markup of your web pages. You can do this in the section for each web page by adding a tag and specifying the deep link as an alternate URI.
For example, the following HTML snippet shows how you might specify the corresponding deep link in a web page that has the URL example://gizmos.
<html>
<head>
<link rel="alternate"
href="android-app://com.example.android/example/gizmos" />
...
</head>
<body> ... </body>
For more details, see the references here:
https://developer.chrome.com/multidevice/android/intents
https://developers.google.com/app-indexing/webmasters/server
https://developer.android.com/training/app-indexing/enabling-app-indexing.html#webpages
And here's a deep link testing tool for Android: https://developers.google.com/app-indexing/webmasters/test.html
Hope that helps.
1 Since the old AOSP browser was replaced by chromium, this is now the default way to handle deep links for recent Android versions. Nonetheless, Android still requires a conditional soltion, because older OS versions still use the AOSP browser.
I have created a Javascript plugin, which supports most of the modern browsers on mobile. But it requires to have deep linking landing pages to be hosted on cross domain(different than universal link url) to work on ios9 Facebook using universal linking. There is also different way to get that working on the Facebook iOS9 using Facebook SDK. I am sharing this if anyone might find this helpful. Currently it does not fallback option, but if falls back to the App Store.
https://github.com/prabeengiri/DeepLinkingToNativeApp
I am Using this Code to for deeplinking.
If the app is installed the app will open up..
If the app is not installed then this remains as it is..
If you wish to add any other condition for app no install then just uncomment the setTimeout code .
<script>
var deeplinking_url = scootsy://vendor/1;
$(document).ready(function(){
call_me_new(deeplinking_url);
});
var call_me_new = function(deeplinking_url){
if(deeplinking_url!=''){
var fallbackUrl ='http://scootsy.com/';
var iframe = document.createElement("iframe");
var nativeSchemaUrl = deeplinking_url;
console.log(nativeSchemaUrl);
iframe.id = "app_call_frame";
iframe.style.border = "none";
iframe.style.width = "1px";
iframe.style.height = "1px";
iframe.onload = function () {
document.location = nativeSchemaUrl;
};
iframe.src = nativeSchemaUrl; //iOS app schema url
window.onload = function(){
document.body.appendChild(iframe);
}
//IF the App is not install then it will remain on the same page.If you wish to send the use to other page then uncomment the below code and send a time interval for the redirect.
/*
setTimeout(function(){
console.log('Iframe Removed...');
document.getElementById("app_call_frame").remove();
window.location = fallbackUrl; //fallback url
},5000);*/
}
};
</script>
setTimeout(function () { if (document.hasFocus()) { window.location = 'URL WILL BEHERE';} }, 2000);
window.location = 'app://';
Need to check document.hasFocus() here because if app is open then playstore url is also open in browser
I also had similar issue, there is a possible alternative for this. If the app is not installed on user's device we can redirect that to some other url.To know more about it Check Here
Example:
Take a QR code
In my case its working fine in opera and chrome browser my deeplink url is
"intent://contentUrl + #Intent;scheme=" +envHost +;package="+envHost+";end";
For other browser create iframe and append the url.
Note -: iframe url append having issue with old device and in firefox its opening app dialog .

Javascript history function not working for web page served from homescreen on iOS 6

I've seen some other posts about iOS 6's new behaviors with Web sites saved to / launched from the home screen. On iOS 5 (and earlier), we were able to use the Javascript History function for our in-app back button. In iOS 6, however, it works if you've only been to one page in the site. But if you have more than one page that you've visited, it throws a page-not-found error. It works fine in Safari (not from the homescreen), and it works if I remove the <meta name="apple-mobile-web-app-capable" content="yes" /> tag. But then I get the ugly browser chrome that I'm trying to avoid.
I've seen similar posts about the changes to iOS 6 no longer sharing data with Safari, but I was hoping someone had run into a similar issue with the history information being stored / used for the homescreen version of the apps in iOS 6.
We're using this call:
Again, it's working fine from Safari, fine in all of the old operating systems. But it fails on iOS 6 from the homescreen when there are more than two pages that the user has clicked on.
My understanding is that if you add the apple-mobile-web-app-capable tag - it caches the page that is bookmarked to the home screen.
Any subsequent requests once the bookmark is launched will cause the safari browser to launch the url (with ugly chrome added).
You could do some basic error checking - if there is any history:
function GoBack() {
if(history.length) {
history.back();
return false;
}
return true; //follow the regular link
}
And you really should be giving your urls a proper href value instead:
Have your tried
onclick="history.go(-1)"
This simple command should work.
Try one of them
window.history.pushState
http://thelink.is/history-api-ios-bug
OR
window.history.pushState(data, title, 'a/new/url#');
OR
window.history.pushState(data, title, 'a/new/url');
window.location.hash = 'new';

Categories