DeviceMotion and DeviceOrientation in WKWebView iOS 13

2.7k Views Asked by At

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)!))
2

There are 2 best solutions below

0
Nikunj Acharya On BEST ANSWER

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

0
TouchBoarder On

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