1

I want to use DeviceMotion and DeviceOrientation events in WKWebView in iOS 13+. I am using below code

<html>
    <style>
        #container{
            margin: 20px; 
            padding: 20px
        }
        #deviceType{
            text-align: center; 
            font-family: Arial, Helvetica, sans-serif; 
            font-size: 3rem;
            font-weight: bold; 
            color: #08f
        }
        #permission{
            padding: 2rem 5rem;
            background: #08f;
            color: white; 
            margin-top: 30;
            font-family: Arial, Helvetica, sans-serif; 
            font-size: 3rem;
            border: none; 
            border-radius: 1rem
        }
        #permissionStatus{
            text-align: center; 
            font-family: Arial, Helvetica, sans-serif; 
            font-size: 2.5rem;
            font-weight: 600; 
            color: red;
            margin-top: 30px
        }
    </style>
    <body>
        <div id="container">
                <div id="deviceType"></div>
                <div style="text-align: center">
                    <button id="permission">Ask for permission</button>
                </div>
                <div id="permissionStatus">Pending</div>
        </div>
    </body>
    <script>

        if (typeof DeviceMotionEvent.requestPermission === 'function') {
            document.getElementById('deviceType').innerText = 'iOS 13'
            document.getElementById('permission').addEventListener('click', function () {
                console.log('button clicked')
                DeviceMotionEvent.requestPermission().then(response => {

                    // This is showing "denied" without showing any permission popup
                    console.log(response)
                    document.getElementById('permissionStatus').innerText = response

                }).catch(console.error)
            });
        } else {
            // ignore this case for processing
            console.log('non iOS 13')
            document.getElementById('deviceType').innerText = 'non iOS 13'
        }
    </script>
</html>

This webpage is working both in safari and chrome and asking permission to use device motion as shown below

Images:

Ask permission on chrome

Status will be updated based on I click Allow or Cancel

enter image description here

But in my app inside I am using WKWebView and When I press Ask Permission Button, It is not showing any alert for asking permission and it is directly setting status to Denied. (shown below).

enter image description here

Please guide me if I am doing something wrong or any extra stuffs required from WKWebView side. Here is my iOS WKWebView Code. I don't know if changes in WKUserContentController or WKWebViewConfiguration are required.

self.webView = WKWebView(frame: .zero)
self.webView.translatesAutoresizingMaskIntoConstraints = false

// Add the webview as a subview of MTKView
self.view.addSubview(self.webView)

self.webView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
self.webView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
self.webView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
self.webView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true


let websiteDataTypes = NSSet(array: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
let date = Date(timeIntervalSince1970: 0)
WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes as! Set<String>, modifiedSince: date, completionHandler:{ })

self?.webView.load(URLRequest(url: URL(string: url)!))
TouchBoarder
  • 6,422
  • 2
  • 52
  • 60
Nikunj Acharya
  • 767
  • 8
  • 19
  • Are you using http or https? Some apis require https. I’ve used motion API in Capacitor apps, which use WKWebView without problems – jcesarmobile Nov 23 '19 at 14:56
  • I am using https. My project is built with iOS 13 build and XCode 11.2. I am not able to understand why it is not working on my app because both chrome and safari uses WKWebView and same site is working on both. Can you please confirm that same this is working on your side even after building project with new XCode and iOS 13. That would be appreciated. – Nikunj Acharya Nov 24 '19 at 18:32
  • We are currently struggling with the same issue. There is an open ticket here, that was created by another guy who has a similar problem: https://bugs.webkit.org/show_bug.cgi?id=203287 – Maksym Musiienko Dec 09 '19 at 10:29
  • Have you tried using `uiDelegate ` ? – Nikunj Acharya Dec 09 '19 at 11:06
  • replied this before seeing the answer. This is really really weird but it did work :D Thank you! – Maksym Musiienko Dec 09 '19 at 11:39
  • 1
    Well it's not that weird. Read `WKUIDelegate` docs https://developer.apple.com/documentation/webkit/wkwebview/1415009-uidelegate. It is saying that "presenting native user interface elements on behalf of a webpage". So if webpage needs to show `UIAlertController`, it should confirms this protocol – Nikunj Acharya Dec 09 '19 at 13:26
  • My bad, haven't noticed that in the docs. Nice observation. Thanks again. – Maksym Musiienko Dec 09 '19 at 14:14

2 Answers2

5

I tried using uiDelegate and it worked

Just added one line inside viewDidLoad

webView.uiDelegate = self

Also you will have to confirm type of ViewController to WKUIDelegate. That's it

Nikunj Acharya
  • 767
  • 8
  • 19
0

On Xamarin iOS (Xamarin.Forms) you can inject the permission request script with the EvaluateJavaScript method on the WkWebView when it is ready:

webView.EvaluateJavaScript("DeviceMotionEvent.requestPermission().then(response => { if (response == 'granted') {window.addEventListener('devicemotion', (e) => {})}}).catch(console.error)");

If using a custom WkWebView renderer the script can be injected when setting the webView control in OnElementChanged (must implement IWKUIDelegate if this bug is still around https://bugs.webkit.org/show_bug.cgi?id=203287)

Example:

// do this when setting up the webview control in OnElementChanged
                //enable device motion sensors permission script:
                //https://medium.com/flawless-app-stories/how-to-request-device-motion-and-orientation-permission-in-ios-13-74fc9d6cd140
                var source =
                "function requestSensorPermission() {" +
                "   if (typeof(DeviceMotionEvent) !== 'undefined' && typeof(DeviceMotionEvent.requestPermission) === 'function') {" +
                "       DeviceMotionEvent.requestPermission() .then(response => {" +
                "           if (response == 'granted') { " +
                "               window.addEventListener('devicemotion', (e) => { })" +
                "           }" +
                "       }).catch(console.error)" +
                "   }" +
                "}";
                var script = new WKUserScript(new NSString(source), WKUserScriptInjectionTime.AtDocumentEnd, true);
                wkWebView.Configuration.UserContentController.AddUserScript(script);

Then you can call yourCustomWebView.EvaluateJavaScript("requestSensorPermission()") in your code behind when WkWebView is ready.

EvaluateJavaScript: https://learn.microsoft.com/en-us/dotnet/api/webkit.wkwebview.evaluatejavascript?view=xamarin-ios-sdk-12

Custom WkWebView Renderer: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/hybridwebview#create-the-custom-renderer-on-ios

TouchBoarder
  • 6,422
  • 2
  • 52
  • 60