How to pass parameters to a dynamic link from flutter? - flutter

I want to navigate a user to a particular page on clicking a shared link based on the id passed in that link. I use dynamic link of Firebase for that. after configuring a dynamic link in the Firebase console manually. I use this code to create a link when sharing an app:
Future<Uri> createDynamicLink(String id) async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://asbdf.page.link',
link: Uri.parse('https://aspdf.page.link/createpost?id=$id'),
androidParameters: AndroidParameters(
packageName: 'com.sample.aspdf',
minimumVersion: 1,
),
);
print(parameters.link);
final ShortDynamicLink shortLink = await dynamicLinks.buildShortLink(parameters);
final Uri shortUrl = shortLink.shortUrl;
return shortUrl;
}
The sharing link works fine. After sharing the link on social media (whatsapp), when I click on that link, the app opens and causes an error. This is the code to retrieve deeplink:
final Uri deepLink = data.link;
print("deeplink found");
print(deepLink);
String? id = deepLink.queryParameters['id'];
print(id.toString());
Get.offAll(()=>AuthStatus(uid: id!));
This is because the app is opening the static deeplink which I configured in the console manually, not the link which was created programatically from the above code. So no parameters are taken by the link and the value of the id variable becomes null and causes an error. How can I fix this problem?

Related

Flutter Dynamic linking not available for web apps?

My Use Case:
Users in my app can create lists of items. I want the users to be able to share a link to one of their lists.
I want individuals who click the shared link to see the list of items in a web browser and not need the app installed.
Create the Dynamic Link
The first thing I need to do is create a dynamic link for a user to share. I struggled with this at first and then looked at this question here: Flutter - How to pass custom arguments in firebase dynamic links for app invite feature?
After looking at that I build my own class like so:
class PackDynamicLinkService {
Future<Uri> createDynamicLink({required String packID}) async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
// This should match firebase but without the username query param
uriPrefix: 'ttps://appName.app/p',
// This can be whatever you want for the uri, https://yourapp.com/groupinvite?username=$userName
link: Uri.parse('https://appName.app/p?pack=$packID'),
androidParameters: const AndroidParameters(
packageName: 'com.test.demo',
minimumVersion: 1,
),
iosParameters: const IOSParameters(
bundleId: 'com.test.demo',
minimumVersion: '1',
appStoreId: '',
),
);
final dynamicLink = await FirebaseDynamicLinks.instance.buildShortLink(
parameters,
shortLinkType: ShortDynamicLinkType.unguessable,
);
return dynamicLink.shortUrl;
}
}
I then called that function in my app and I am able to get a URL that looks like this: https://appName.app/p?pack=lVeSBUHoLX52zPqAiB9A
So far so good. Now I just need to click the link and read the parameter $packID that I passed to it inside my web app. Then I can route them to the correct view and display the list.
Processing Dynamic Link
in my marin.dart I tried to retrieve the params with:
//get link stuff
final PendingDynamicLinkData? initialLink =
await FirebaseDynamicLinks.instance.getInitialLink();
if (initialLink != null) {
final Uri fullLink = initialLink.link;
print(fullLink.queryParameters['pack']);
}
but when I upload to firebase hosting to see if this code works for testing, I get this error:
Uncaught MissingPluginException(No implementation found for method
FirebaseDynamicLinks#getInitialLink on channel
plugins.flutter.io/firebase_dynamic_links)
After doing some more research it seems that firebase_dynamic_links package may not be available for web? So does that mean my original use case is not possible with flutter at this time?
You would want to take the link received and parse it using something like:
var PendingDynamicLinkData? initialLink =
await FirebaseDynamicLinks.instance.getInitialLink();
if (kIsWeb) {
String link = Uri.base;
initialLink = await
FirebaseDynamicLinks.instance.getDynamicLink(Uri.parse(link));
}
if (initialLink != null) {
final Uri fullLink = initialLink.link;
print(fullLink.queryParameters['pack']);
}
Here, we are checking if its a web app and then we can parse the dynamic link and get the info for it. We just check for the Uri that was used in our web app.

Custom Parameters are always Null | Firebase Dynamic Links

What I Want to Do
When the user taps the URL, it launches the app and pops up a page within the app based on the included custom parameters.
Problem
I succeeded in launching an Android or iOS app by tapping the URL, but the custom parameter is always null.
What I Did
The URL that users tap is as follows.
https://example.page.link/test/?link=https://test.example.com/?id=${id}&apn=com.example.app
id is custom parameter that I want to get when this URL is called.
I created link on Firebase Console like example.page.link/test.
In initState, call initDeepLinks function.
// openPage opens detail page with id
Future<void> initDeepLinks() async {
final PendingDynamicLinkData? initialLink =
await FirebaseDynamicLinks.instance.getInitialLink();
if (initialLink != null) {
final Uri deepLink = initialLink.link;
print("A: " + deepLink.queryParameters["id"]!);
openPage(deepLink.queryParameters["id"]!);
}
FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) {
print("B: " + dynamicLinkData.link.queryParameters["id"]!);
openPage(dynamicLinkData.link.queryParameters["id"]!);
}).onError((error) {});
}
But those two print()s print only A: or B: .
I checked URL that contains ?id=$id and it is correct.
Tried other URL
When I change the URL to
https://example.page.link/?link=https://test.example.com/?id=${id}&apn=com.example.app
(removed `/test` path)
It works with custom parameters only on Android.
But do same on iOS, the browser shows https://test.example.com page and app doesn't appear.
What should I do to make custom parameters?

Google Assistant make GET request and reply with server response

I'd like to create an action in Google Assistant such that when a voice command is issued, the Assistant will make a GET request to a URL, like http://example.com/response.txt and just read out the plaintext response. How do I go about doing that?
You would need to create an Action using Actions Builder or Dialogflow.
This Action would start with a 'Default Welcome Intent' that you should connect it to a webhook:
This webhook can be written simply using a language like Node.js
import {conversation} from '#assistant/conversation'
const fetch = require('node-fetch')
const app = conversation()
const URL = 'http://example.com/response.txt'
app.handle('Default Welcome Intent', async conv => {
const apiResponse = await fetch(URL)
const text = await apiResponse.text()
conv.add(text)
})
Depending on whether you just want static information or not, you may want to then add a transition to 'end conversation' to close it out.

Flutter open whatsapp with text message

I want to open whatsapp from my Flutter application and send a specific text string. I'll select who I send it to when I'm in whatsapp.
After making some research I came up with this:
_launchWhatsapp() async {
const url = "https://wa.me/?text=Hey buddy, try this super cool new app!";
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
Which works ok ish, however there are two problems:
As soon as I make the text string into multi words it fails. So if I change it to:
_launchWhatsapp() async {
const url = "https://wa.me/?text=Hey buddy, try this super cool new app!";
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
Then the Could not launch $url is thrown.
I have whatsapp already installed on my phone, but it doesn't go directly to the app, instead it gives me a webpage first and the option to open the app.
Here is the webpage that I see:
Any help on resolving either of these issues would be greatly appreciated.
Thanks
Carson
P.s. I'm using the Url_launcher package to do this.
From the official Whatsapp FAQ, you can see that using "Universal links are the preferred method of linking to a WhatsApp account".
So in your code, the url string should be:
const url = "https://wa.me/?text=YourTextHere";
If the user has Whatsapp installed in his phone, this link will open it directly. That should solve the problem of opening a webpage first.
For the problem of not being able to send multi-word messages, that's because you need to encode your message as a URL. Thats stated in the documentation aswell:
URL-encodedtext is the URL-encoded pre-filled message.
So, in order to url-encode your message in Dart, you can do it as follows:
const url = "https://wa.me/?text=Your Message here";
var encoded = Uri.encodeFull(url);
As seen in the Dart Language tour.
Please note that in your example-code you have put an extra set of single quotes around the text-message, which you shouldn't.
Edit:
Another option also presented in the Whatsapp FAQ is to directly use the Whatsapp Scheme. If you want to try that, you can use the following url:
const url = "whatsapp://send?text=Hello World!"
Please also note that if you are testing in iOS9 or greater, the Apple Documentation states:
Important
If your app is linked on or after iOS 9.0, you must declare the URL schemes you pass to this method by adding the LSApplicationQueriesSchemes key to your app's Info.plist file. This method always returns false for undeclared schemes, whether or not an appropriate app is installed. To learn more about the key, see LSApplicationQueriesSchemes.
So you need to add the following keys to your info.plist, in case you are using the custom whatsapp scheme:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>whatsapp</string>
</array>
till date: 27-06-2022
using package: https://pub.dev/packages/url_launcher
dependencies - url_launcher: ^6.1.2
TextButton(
onPressed: () {
_launchWhatsapp();
},
)
_launchWhatsapp() async {
var whatsapp = "+91XXXXXXXXXX";
var whatsappAndroid =Uri.parse("whatsapp://send?phone=$whatsapp&text=hello");
if (await canLaunchUrl(whatsappAndroid)) {
await launchUrl(whatsappAndroid);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("WhatsApp is not installed on the device"),
),
);
}
}
Here is new update way...
whatsapp() async{
var contact = "+880123232333";
var androidUrl = "whatsapp://send?phone=$contact&text=Hi, I need some help";
var iosUrl = "https://wa.me/$contact?text=${Uri.parse('Hi, I need some help')}";
try{
if(Platform.isIOS){
await launchUrl(Uri.parse(iosUrl));
}
else{
await launchUrl(Uri.parse(androidUrl));
}
} on Exception{
EasyLoading.showError('WhatsApp is not installed.');
}
}
and call whatsapp function in onpress or ontap function
For using the wa.me domain, make sure to use this format...
https://wa.me/123?text=Your Message here
This will send to the phone number 123. Otherwise, you will get an error message (see? https://wa.me/?text=YourMessageHere ). Or, if you don't want to include the phone number, try this...
https://api.whatsapp.com/send?text=Hello there!
Remember, wa.me requires a phone number, whereas api.whatsapp.com does not. Hope this helps!
I know it is too late for answering this, but for those who want the same functionality, the current way is to do it like this:
launchUrl(Uri.parse('https://wa.me/$countryCode$contactNo?text=Hi'),
mode: LaunchMode.externalApplication);
if you will use URL Launcher then the whatsapp link will be open on web browser. So you need to set parameter - not to open on safari browser. The complete code you can find on this flutter tutorial.
But for your case use below code.
await launch(whatappURL, forceSafariVC: false);
Today i am adding solution its working fine on my desktop and phone
Add 91 if your country code is +91
Remember not add any http or https prefix otherwise wont work.
whatsapp://send?phone=9112345678&text=Hello%20World!

How to get auth code for Google OAuth using the Mongo Stitch React-Native SDK?

From the docs it seems like there is no other way to sign-in using Google other than using the GoogleCredential constructor which takes an authCode as a mandatory parameter, how should I get it?
For an example of [[loginWithRedirect]], see Facebook Authentication
Also, there are multiple references in the docs to a function called loginWithRedirect, but they don't link anywhere and there is no property in the auth object called loginWithRedirect.
Indeed, the RN and server SDKs do not support the redirect concept. You have to get your own authCode.
Stitch's GoogleCredential constructor just expects a valid server auth code so that the Stitch service can use offline access.
Use a third-party OAuth module
I had no luck using the official google-auth-library SDK with RN. I was able to make it work (on iOS, at least -- haven't tried Android, yet) with react-native-google-signin from react-native-community. The installation process is a bit involved, so be sure to follow their instructions carefully!
I will show how I used this specific library to sign in. Hopefully this information can be applied to other OAuth libraries and other Authentication providers (e.g. Facebook).
Configure GoogleSignin
The webClientId must be specified and must match the Client ID under the Google Oauth2 configuration on the Stitch UI (see screenshot). The iosClientId is found in the GoogleService-Info.plist you download after following these steps. Finally, set offlineAccess to true.
If you use the Google iOS SDK directly or another library, note that webClientId is called serverClientID and iosClientId is simply called clientId.
Here's my configure code (see my complete App.js file):
componentDidMount() {
// ...
GoogleSignin.configure({
webClientId: '<id>', // from Stitch UI > Users > Providers > Google
offlineAccess: true,
iosClientId: '<id>', // CLIENT_ID in GoogleService-Info.plist
});
}
Render GoogleSigninButton
react-native-google-signin provides a nice button to use, which I rendered out (see screenshot):
const loginButton = <GoogleSigninButton
style={{ width: 192, height: 48 }}
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Dark}
onPress={this._onPressLogin}
disabled={this.state.isSigninInProgress}
/>
Give Stitch the serverAuthCode from GoogleSignin
My _onPressLogin function uses GoogleSignin to get the serverAuthCode. It then passes that code to Stitch:
_onPressLogin = async () => {
// They recommend calling this before signIn
await GoogleSignin.hasPlayServices();
// Call signIn to get userInfo
const userInfo = await GoogleSignin.signIn();
// Check if serverAuthCode was received -- it will be null
// if something wasn't configured correctly. Be sure to
// log out after changing a configuration.
const {serverAuthCode} = userInfo;
if (serverAuthCode === null) {
throw new Error('Failed to get serverAuthCode!');
}
try {
// Pass serverAuthCode to Stitch via GoogleCredential
const user = await this.state.client.auth.loginWithCredential(new GoogleCredential(serverAuthCode));
console.log(`Successfully logged in as user ${user.id}`);
this.setState({ currentUserId: user.id });
} catch(err) {
console.error(`Failed to log in anonymously: ${err}`);
this.setState({ currentUserId: undefined })
}
Logging out
I found I had to log out several times while testing (and figuring out which client IDs to use where), or else serverAuthCode would come back null. It was good to have the logout button visible at all times. My logout code looks like this:
_onPressLogout = async () => {
await GoogleSignin.revokeAccess();
await GoogleSignin.signOut();
const user = await this.state.client.auth.logout();
console.log(`Successfully logged out`);
this.setState({ currentUserId: undefined })
}
I hope this helps!