Igor
Igor

Reputation: 609

Unable to get Android App Link to work in an Android app written in Flutter

I am trying to implement Moneris hosted pay page from a flutter mobile app but this question is relevant to any app that wants to implement Android App Links. In order to redirect back from the hosted pay page, I need to implement Android App Link (haven't gotten to do iOS version yet). Based on this article, in order for App Links to work, one needs:

  1. Identify a redirect URL on the Moneris hosted pay page (or on the page where a redirect might take place, in case of a generic example);
  2. Modify AndroidManifest.xml to associate redirects with activities;
  3. Implement a way in Flutter to intercept App Links;
  4. Place the Digital Asset Links JSON file on the web site (same domain as redirect URL) in the .well-known folder.

For #1, I have identified 2 URLs, one for approved payments (https://example.com/moneris_approved) and one for declined payments (https://example.com/moneris_declined). URLs have to be in https for the whole thing to work. Moneris can reply with a POST with XML, POST with parms or GET with parms. Tried all three.

For #2, I have modified AndroidManifest.xml both by hand and with help of Android Studio. Relevant pieces look like this:

<application
    android:name="io.flutter.app.FlutterApplication"
    android:label="<label>"
    android:icon="@mipmap/ic_launcher">
    <activity
        android:name=".MainActivity"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        ...              
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <intent-filter android:autoVerify="true">
            <action android:name="android.intent.action.VIEW" />    
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />    
            <data
                android:scheme="https"
                android:host="example.com"
                android:pathPattern="/moneris_approved" />
        </intent-filter>    
        <intent-filter android:autoVerify="true">
            <action android:name="android.intent.action.VIEW" />   
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />    
            <data
                android:scheme="https"
                android:host="example.com"
                android:pathPattern="/moneris_declined" />
        </intent-filter>    
    </activity>
</application>

For #3, I am using uni_links package which takes care of channeling incoming App Links to my app.

For #4, I have created and uploaded the assetlinks.json file and placed in the right folder. Included both debug and release SHA256 fingerprints. The file looks like this:

[
    {
        "relation": ["delegate_permission/common.handle_all_urls"],
        "target": {
            "namespace": "android_app",
            "package_name": "com.example.<name>",
            "sha256_cert_fingerprints":
            ["........"]
        }
    }
]

Now, after doing all that, when Moneris redirects to provided URLs, I am seeing a 404 page coming from my hosting site.

To verify the setup, I have:

At this point, I don't know how else to test it or what the problem is. I don't think the problem is with my app but rather soemthing is not closing the loop between Moneris redirect and it coming back to my app.

Update 1

I devised a testing approach like this:

  1. Created a link-test page on my site with links mimicking redirects (i.e. same host/path as in the app's AndroidManifest.xml;
  2. Created a simple Java Android App using Android Studio. Using App Link Assistant I updated its AndroidManifest, created intents and reacted to those coming in. Also updated the assetlinks.json file on my website. Tested it with the link-test page running on my emulator and everything worked as expected. App opened up ok.
  3. Repeated #2 but this time with a Flutter app using the uni_links package. Went throught he same steps of creating slightly different links on my link-test page, updating AndroidManifest and assetlinks.json file. Tested it with the link-test page running on my emulator and everything worked as expected. App opened up ok.
  4. Run the app I am working on on the emulator and put the links I am expecting to get from Moneris on my link-test page and tsted on the emulator. Everything worked as expected. App opened up ok.

So now my question is: what is the difference between me clicking on a link on my page (HTTP GET) vs. Moneris redirecting to the same link using HTTP GET? Me clicking on the link works. Moneris redirect does not.

Upvotes: 3

Views: 3235

Answers (2)

Pavlo Ostasha
Pavlo Ostasha

Reputation: 16729

I can see that you want to handle deep link right in the flutter code. That is possible but you have to use one of the libraries for that - for example this.

If you want to do it by yourself you have to create a platform specific Method Channels for that. This answer shows how to do it.

Also you can find a more detailed explanation here

Hope it helps.

Upvotes: 2

Mohamed Elrashid
Mohamed Elrashid

Reputation: 8619

This soution is not working for this case🙄🤷‍♀️

thanks for clarification. Unfortunately, Moneris only supports http and https schemas so using com.googleusercontent.apps as schema will not work for me. And while I get that it works for you, your implementation contradicts my understanding of how Android App Links should work

01.The problem

Failed to lanch the app after Redirect

02.The analysis of the problem

=> (1) App (lanch browser)👍

==> (2) browser ( Moneris.com) 👍

===> (3) browser (redirct to example.com) 👍

=====> (4) browser (404 page)❌

======> (5) failed because the app is not launched❌

03.Why Step 4 failed

  • because you used a real domain schema

  • the browser used the DNS not ask the OS to lanch the app

04.Solution

  • Use com.googleusercontent.apps Url

05.Example returnUrl solution

String returnUrl =
    "com.googleusercontent.apps.932931520452-buv2dnhgo7jjjjv5fckqltn367psbrlb:/approved)";
String cancelUrl =
    "com.googleusercontent.apps.932931520452-buv2dnhgo7jjjjv5fckqltn367psbrlb:/declined)";

06.Example manifest

    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.e042_flutter_paypal_f">
        <application android:name="io.flutter.app.FlutterApplication" android:label="e042_flutter_paypal_f" android:icon="@mipmap/ic_launcher">
            <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">

                <meta-data android:name="io.flutter.app.android.SplashScreenUntilFirstFrame" android:value="true" />
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
                <intent-filter>
                    <action android:name="android.intent.action.VIEW"/>
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.BROWSABLE" />
                    <!-- Custom Path data -->
                    <data android:path="/auth" android:scheme="com.googleusercontent.apps.932931520452-buv2dnhgo7jjjjv5fckqltn367psbrlb"/>
                </intent-filter>
            </activity>
        </application>
    </manifest>

⚠ Warning ⚠ If there is a Client Secret stored in the App (i didn't use Moneris, but i asume there is a Client Secret), and the app is not inted for the internal use of the company , it's very very bad


Ref.

Upvotes: 1

Related Questions