Http links on Flutter not working on Android devices - android

With the help of uni_links library, I am connecting the payment screen in the browser with the app, to link back to the app once payment is successful. It all works as expected on iOS, and app is opened with return url. But on Android callback is not even called, that notifies me about the return url, even though the app is opened, meaning http linking part works.
This is what I've added in Android Manifest file:
<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="www.redirect.mydomain.eu"
android:pathPrefix="/return_url"/>
</intent-filter>
And this is the callback from uni_links that I am listening to in order for it to trigger with the return url string, but it doesn't trigger on Android at all:
_subscription = getLinksStream().listen((String link) {
// Handle success case
}, onError: (err) {
// Handle exception by warning the user their action did not succeed
});
Any idea why this is not working on Android at all?

Related

Flutter Firebase email link auth - dynamic link is not working for me

I've followed the steps in this guide.
My dynamic link is https://XXXXX.page.link/amTC and it's deep link is https://link.YYYYY.com.
I'm able to successfully send an email link with this,
var acs = ActionCodeSettings(
url: 'https://XXXXX.page.link/amTC',
handleCodeInApp: true,
iOSBundleId: Constants.iosBundleId,
androidPackageName: Constants.androidPackageName,
androidInstallApp: false,
androidMinimumVersion: '12');
FirebaseAuth.instance.sendSignInLinkToEmail(email: 'mytest98723151#gmail.com', actionCodeSettings: acs);
The resulting email contains a link that appears to be well formed (it looks like https://XXXXX.page.link/?link=https//myfirebasehost/__auth/action?apiKey=xxx&lots_of_fancy_query_params) . However my confusion is around how to handle that link in my Android app (haven't tried iOS yet).
If I add the following 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"/>
<data android:host="link.YYYYY.com" android:scheme="https"/>
</intent-filter>
then clicking the email link brings my app back into the foreground and this gets triggered
FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) async {
final Uri deepLink = dynamicLinkData.link;
bool foo = FirebaseAuth.instance.isSignInWithEmailLink(deepLink.toString());
logger.d('deepLink is email link? $foo');
logger.d(dynamicLinkData.asMap());
}
But the output below shows that the link isn't really working, presumably because dynamicLinkData is simply my deep-link url with no other data attached, when what's needed is the full dynamic link.
deepLink is email link? false
{
"ios": null,
"android": {
"clickTimestamp": 1665438309155,
"minimumVersion": 0
},
"link": "https://link.YYYYY.com",
"utmParameters": {}
}
[Note that if I simply paste the entire link from the e-mail into my app and pass it to FirebaseAuth.instance.isSignInWithEmailLink('link-from-email') it returns 'TRUE'.]
The way I expected this should work is that I'd use an intent filter like the one below, containing the dynamic link host, not the deep link. And then by clicking the email link FirebaseDynamicLinks.instance.onLink.listen would receive the entire dynamic link I clicked. But that doesn't happen. With the below intent filter my app is never invoked when I click the dynamic link in the email.
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="XXXXX.page.link" android:scheme="https"/>
</intent-filter>
I don't understand how to set up my app to properly receive the dynamic link when it's clicked from the e-mail. If anyone can explain what I'm doing wrong I'd be grateful. Thanks!
Got the answer from this post thanks to #hansaplast. i.e In the ActionCodeSettings constructor call, using
androidMinimumVersion: '1'
and setting the intent-filter to the firebase host as below solved it.
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="ZZZZ-123456.firebaseapp.com" android:scheme="https"/>
</intent-filter>

Dynamic link seems to not survive to the installation process

My MainActivity manages the deep link this way
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
intent?.let {
checkDynamicLink(intent)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
checkDynamicLink(intent)
}
private fun checkDynamicLink(intent: Intent) {
FirebaseDynamicLinks.getInstance()
.getDynamicLink(intent)
.addOnSuccessListener(this) { dynamicLink ->
dynamicLink?.link?.let { deepLink ->
viewModel.postDeepLink(deepLink)
}
}
}
The viewModel is shared; once the user is logged in, the home fragment takes the deep link and the NavController handles it.
It works perfectly when debugging and also when installing the production version of the app through Android Studio (minified or not). The problem occurs when I install the production app through the play store.
When opening the dynamic link the Play Store is opened; I install the app and then click on "Continue" (the fact I see "Continue" rather than "Open" should mean it recognizes there's a dynamic link with which opening the app).
I open the app, then log in; when it arrives to the home fragment, apparently, there's no deep link to be managed. It should open a fragment, but it doesn't.
More strange: if I install the app through the dynamic link and then I open it through the launcher (rather than the "Continue" button on the play store) the dynamic link and the deep link are correctly managed.
It seems to be a Play Store bug. My question is, is there something I'm forgetting?
The following is the activity's intent-filter in the manifest:
<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:host="#string/firebase_dynamic_links_domain_uri_prefix"
android:scheme="https" />
<data
android:host="#string/firebase_dynamic_links_domain_uri_prefix"
android:scheme="http" />
</intent-filter>
looking at firebase dynamic links documentation, there is several ways to setupa dynamic link.
I would recommend you check that the package name on the dynamic link is set to match the package name of your production app.
The problem was related to the AndroidManifest and how the activity was declared:
<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:host="#string/firebase_dynamic_links_domain_uri_prefix"
android:scheme="https" />
<data
android:host="#string/firebase_dynamic_links_domain_uri_prefix"
android:scheme="http" />
</intent-filter>
<nav-graph android:value="#navigation/nav_graph" />
</activity>
The nav_graph tag caused the dynamic link to be automatically managed by the app, so when the app was launched through the play store the dynamic link's deep link was automatically managed, but the user wasn't logged in so the fragment wasn't shown (so it wasn't apparently not managed).

Flutter application with android fails to capture callback url

I am trying to authenticate a flutter application against Spotify.
For this, I use the flutter_web_auth package. I have a button to authenticate against Spotify.
Once user clicks the button, the following function operates:
onPressed: () async {
final spotifyAuthURL = Uri.https(
'accounts.spotify.com',
'/authorize',
{
'response_type': 'code',
'client_id': dotenv.get('SPOTIFY_CLIENT_ID'),
'redirect_uri':
'https://vinyl_app_spotify.com/callback',
'scope': 'user-read-private user-read-email',
},
);
final result = await FlutterWebAuth.authenticate(
url: spotifyAuthURL.toString(),
callbackUrlScheme:
'https://vinyl_app_spotify.com/callback',
);
},
I've also added the following activiy to the AndroidManifest.xml file as I should have done according to the flutter_web_auth package:
<activity android:name="com.linusu.flutter_web_auth.CallbackActivity" >
<intent-filter android:label="flutter_web_auth">
<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://vinyl_app_spotify.com/callback" />
</intent-filter>
</activity>
So after I click my application button, I do get access to Spotify, then the redirect url kicks in, but I just see this:
So my android emulator could not capture the callback url.
What is my mistake? Any advice..

Deep Link - Https unexpectedly redirecting to chrome

I am working on adding an OAuth flow to a Trello integration within my app. The idea is using deep linking to consume the response within the app itself (there is no server between the app and the database - I am using room).
I have everything working up to this point except the callback redirect portion, and it works on my real device, rather than the emulator.
This is the code that begins the OAuth flow.
val connection = object:CustomTabsServiceConnection() {
override fun onCustomTabsServiceConnected(name: ComponentName, client: CustomTabsClient) {
val builder = CustomTabsIntent.Builder()
val customTabsIntent = builder.build()
client.warmup(0)
var authUrl = "$TOKEN_URL?key=$API_KEY&scope=read&callback_method=fragment&return_url=${AuthenticationManager.HTTPS_REDIRECT_URL}&expiration=never&name=$NAME&integration=${integration.id}"
customTabsIntent.launchUrl(context, Uri.parse(authUrl))
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
bindCustomTabsService(context, "com.android.chrome", connection);
Manifest
<activity
android:name="com.myapp.MainActivity"
android:screenOrientation="sensor"
android:windowSoftInputMode="adjustPan"
android:launchMode="singleTop"
android:configChanges="uiMode">
<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.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="pomodoro" android:host="oauth.myapp.com"/>
<data android:scheme="https" android:host="myapp.com"/>
</intent-filter>
</activity>
At this point it is redirected to my webpage, which I verified on my real device redirects to my app (so it can consume the intent and get the necessary token). I am wondering if when I selected Always use for the chrome browser (when initially opening a webpage in the emulator), that this basically overrides my deep link? Is that possible? Also using a different scheme isn't possible, as Trello forces uses to use https/http as the trusted redirect/callback urls?
This is related to my misunderstanding of deeplinks vs AppLinks. I want to treat this more as an AppLink vs a deeplink, meaning the verification has already happened that this URL belongs to my app (via a file on my domain). For this verification to happen I need the verification file at the appropriate url, if it is not there - the verification cannot happen. Which happens for each host/scheme, and must verify all match.
The solution was to remove the scheme/host that isn't associated with the app/domain, to allow AutoVerify.
"Only if the system finds a matching Digital Asset Links file for all hosts in the manifest does it then establish your app as the default handler for the specified URL patterns." https://developer.android.com/training/app-links/verify-site-associations
After updating my manifest to the below it worked as expected, and redirected the OAuth flow as expected.
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="https" android:host="myapp.com"/>
</intent-filter>

React Native Android deep linking url not passed through

I've got deep linking to work on a basic level with our React native app using the excellent tutorial at https://medium.com/react-native-training/deep-linking-your-react-native-app-d87c39a1ad5e. Works a treat on iOS, however on Android I don't seem to get the url passed back when it links back into my app:
class App extends Component {
componentDidMount() {
if (UtilsCommon.isNative) {
RNSplashScreen.hide();
if (UtilsCommon.isIos) {
Linking.addEventListener("url", this.handleOpenURL);
} else {
console.log("registering deep linking on Android");
Linking.getInitialURL().then(url => {
console.log("url", url);
});
}
}
}
componentWillUnmount() {
Linking.removeEventListener("url", this.handleOpenURL);
}
handleOpenURL = event => {
console.log(event.url);
};
So on iOS, the link back from the test page happily goes into handleOpenURL and I see the entire url that was linked to come out in the console. However, on Android, we always get url as being null. So whilst it re-opens the app, I can't determine where it should go due to this. I added the following intent to AppManifest.xml:
<intent-filter android:label="filter_react_native">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
I've tried specifying an android:host attribute inside of the data node, but the url still stubbornly remained null. Can anyone tell me what else I need to do?

Categories

Resources