Android, Apple sign in

Viewed 2952

I'm trying to add Apple sign-in functionality to my Android App. I follow the pop-up approach. I'm failing to get it to work.

class AppleLoginWebViewActivity : BaseActivity(), AppleLoginContract.View {

   private val TAG = AppleLoginWebViewActivity::class.java.simpleName

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_apple_login)

       prepareWebView()
   }

   private fun prepareWebView() {

       if (BuildConfig.DEBUG) {
           WebView.setWebContentsDebuggingEnabled(true)
       }

       webView.addJavascriptInterface(
           AppleLoginJavaScriptInterface(),
           "AndroidInterface"
       )

       val webSettings: WebSettings = webView.settings
       webSettings.javaScriptEnabled = true
       webView.webViewClient = MyWebViewClient()
       webView.webChromeClient = MyWebChromeClient()
       webView.settings.loadWithOverviewMode = true
       webView.settings.domStorageEnabled = true
       webView.settings.useWideViewPort = true
   }

   private inner class MyWebViewClient : WebViewClient() {

       override fun onPageFinished(
           view: WebView,
           url: String
       ) { //Calling a javascript function in html page
           Logger.info(TAG, "page started: $url")
           // view.loadUrl("javascript:alert(clickAppleSignInButton())")
           view.loadUrl("javascript:AndroidInterface.showHTML" +
               "('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
       }

       override fun shouldOverrideUrlLoading(
           view: WebView?,
           request: WebResourceRequest?
       ): Boolean {
           return false
       }
   }

   private class MyWebChromeClient : WebChromeClient() {
       override fun onJsAlert(
           view: WebView,
           url: String,
           message: String,
           result: JsResult
       ): Boolean {
           result.confirm()
           return true
       }
   }

   override fun loadUrl(appleLoginLocalUrl: String) {
       webView.loadUrl(appleLoginLocalUrl)
   }
}

and here is the html file that I load

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Apple Sign in</title>
</head>
<body>
<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
<div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
<script type="text/javascript">

     const options = {
       clientId: 'MY_CLIENT_ID',
       scope: 'email name',
       redirectURI: 'MY_REDIRECT_URL',
       state: '',
       usePopup : true
     };
     AppleID.auth.init(options);
 </script>

 <script type="text/javascript">
   function clickAppleSignInButton() {
     document.getElementById("appleid-signin").click();
   }
 </script>

 <script type="text/javascript">
   //Listen for authorization success
   document.addEventListener('AppleIDSignInOnSuccess', successFunction);
   //Listen for authorization failures
   document.addEventListener('AppleIDSignInOnFailure', failureFunction);

   function successFunction(data) {
     //handle successful response
     console.log("success")
     AndroidInterface.onLoginSuccess(data);
   }

   function failureFunction(error) {
     //handle error
     console.log("failure")
     AndroidInterface.onLoginFailed(error);
   }
 </script>
</body>
</html>

SO, in the last step, when I inspect the web view, I can see the authentication data being posted (POST request) to another url inside the web view. But the event listener with AppleIDSignInOnSuccess is never called. there is an error that says "Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('MY_REDIRECT_URL') does not match the recipient window's origin ('https://appleid.apple.com').", source: (0).

So, I have a couple of questions:

  1. How to fix this error?
  2. Why the event listener is not getting called?
  3. Is there a way that I can intercept and parse the POST response from the web view directly?
2 Answers
<script type="text/javascript">

     const options = {
       clientId: 'MY_CLIENT_ID',
       scope: 'email name',
       redirectURI: 'MY_REDIRECT_URL',
       state: '',
       usePopup : true
     };
     AppleID.auth.init(options);
     AppleID.auth.signIn(); //<-- there :)
 </script>
  • Apple wants that redirect url to be full really url, like: https://some.domain.tld/path/to/redirect which supports POST
  • Also not all browsers support usePopup, for example iOS 10.3 block this for me :)

The problem may be that the page hasn't finished loading yet. Try changing

document.getElementById("appleid-signin").click();

to

window.addEventListener('load', function() {
    document.getElementById("appleid-signin").click();
});

You can set up remote debugging with Chrome which will allow you to use Chrome Dev Tools to debug your webview with your device connected. Docs here: https://developers.google.com/web/tools/chrome-devtools/remote-debugging

Related