I am creating a dynamic link to navigate me to a specified page, when trying it on emulator it work fine but when trying it on actual device the link only open the app
Creating the dynamic link
Future<void> createDynamicLink(bool short, int lecID, String lecName) async{
setState(() {
_isCreatingLink = true;
});
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://geneapp.page.link',
link: Uri.parse('https://www.geneapp.com/lecture?lecID=$lecID&lecName=$lecName'),
androidParameters: AndroidParameters(packageName: 'com.example.teams',minimumVersion: 0),
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.short
),
socialMetaTagParameters: SocialMetaTagParameters(
title: "$lecName",
description: "new"
)
);
print("https://geneapp.page.link/lecture?lecID=$lecID&lecName=$lecName");
Uri url;
if (short) {
final ShortDynamicLink shortLink = await parameters.buildShortLink();
url = shortLink.shortUrl;
} else {
url = await parameters.buildUrl();
}
setState(() {
_linkMessage = url.toString();
_isCreatingLink = false;
});
print(url);
Clipboard.setData(new ClipboardData(text: '$url'));
FocusScope.of(context).requestFocus(new FocusNode());
scaffoldKey.currentState?.removeCurrentSnackBar();
scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text("copied",style: TextStyle(fontSize: 16)),
Padding(
padding: EdgeInsets.fromLTRB(10.0,0.0,0.0,0.0),
child: Icon(Icons.check_circle,color: Colors.grey,),
)
],
),
backgroundColor: Colors.green,
duration: Duration(seconds: 3),
));
}
Handling the deep link:
void initDynamicLinks() async{
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
var isLec = deepLink.pathSegments.contains('lecture');
if(isLec){
var lecName = deepLink.queryParameters['lecName'];
var lecID = int.parse(deepLink.queryParameters['lecID']);
print("initDynamicLinks | lecName : $lecName lecID : $lecID");
await _openPDF(lecName, lecID);
}
}
else
print('its null');
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deeplink = data?.link;
if(deeplink != null){
var lecName = deeplink.queryParameters['lecName'];
var lecID = int.parse(deeplink.queryParameters['lecID']);
print("initDynamicLinks | lecName : $lecName lecID : $lecID");
await _openPDF(lecName, lecID);
}
}
_openPDF(String lecName, int lecID) async{
final filename = lecName;
String dir = (await getApplicationDocumentsDirectory()).path;
if (await File('$dir/$filename').exists()){
navigatorKey.currentState.pushNamed('/pdf', arguments: '$dir/$filename');
}
else{
//..
//
navigatorKey.currentState.pushNamed('/pdf', arguments: '$dir/$filename');
}
}
in my main build function I am setting initialRoute to a splash screen,
then in my splash screen initstate I am calling the initDynamicLinks():
There can be various reasons for app not launching, the android device your using, the browser used to launch the link (if a link is copy pasted in chrome they do not work), DynamicLinks setup.
You can try few things
encode your lecName variable in the Long URL.
Send the dynamic-short link over message and try to click and launch the app.
Related
I made a log-in page and made a button for google log-in like this :
Future<String> login_google() async{
FirebaseAuth auth = FirebaseAuth.instance;
GoogleSignIn googleSignIn = GoogleSignIn();
GoogleSignInAccount? account = await googleSignIn.signIn();
GoogleSignInAuthentication authentication = await account!.authentication;
AuthCredential credential = GoogleAuthProvider.credential(
idToken: authentication.idToken,
accessToken: authentication.accessToken);
final authResult = await auth.signInWithCredential(credential);
final user = authResult.user;
print (user?.uid);
print (user?.email);
print('google log-in completed');
return Future.value(user?.uid);
}
...
class _login_pageState extends State<login_page> {
#override
Widget build(BuildContext context) {
// String uid_r = await login_google();
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
toolbarHeight: 1.0,
),
body:Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image( image: AssetImage('asset/logo.png'),),
ElevatedButton(onPressed: (){
login_kakao();
Navigator.of(context).push(MaterialPageRoute(builder: (context) =>main_bone(uid:'')));
}, child: Text('Kakao Log-In')),
ElevatedButton(onPressed: (){
// login_kakao();
final uid = login_google().then(
(value){
Navigator.of(context).push(MaterialPageRoute(builder: (context) =>main_bone(uid: value))); => The button for LOG-IN .
}
);
}, child: Text('Google Log-In'))
],
),
);
}
}
Here I succeeded in log-in and passed only uid thinking that only uid is required. And My firestore rules for accessing is following :
match /post/{document=**}
{
allow read;
allow write:if
auth.uid != null;
}
On the next page, None of the data in collection(post) were shown, which means the log in has disabled on the next class .
Should I pass the whole variables for authentication to next class, for example, auth, credential ?
its called inherited widget, there is a lot method to make your entire app authenticated, not just one class. make a stream builder, listen firebase_auth.authStateChanges()
or you can use a package ( state management ) :
like
flutter_bloc
or
i prefer goRouter
check this video, its chris itself explain how to use it, its even better; work at flutter web too
take look at mine for your reference :
import 'dart:ui';
import 'package:cms_prototype/auth/auth.dart';
import 'package:cms_prototype/home/home.dart';
import 'package:cms_prototype/login/login.dart';
import 'package:cms_prototype/theme.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: const FirebaseOptions(
apiKey: "********",
authDomain: "",
appId: "",
measurementId: "",
storageBucket: "**.com",
messagingSenderId: "**",
projectId: "**"));
final auth = AuthRepo();
await auth.user.first;
final router = GoRouter(
urlPathStrategy: UrlPathStrategy.path,
redirect: (GoRouterState state){
if(auth.currentUser.isEmpty && state.location != '/login'){
return '/login';
}
if(auth.currentUser.isNotEmpty && state.location == '/login'){
return '/';
}
return null;
},
refreshListenable: GoRouterRefreshStream(auth.user),
routes: [
GoRoute(
name: 'home',
path: '/',
pageBuilder: (context, state) => MaterialPage(
key: state.pageKey,
child: const HomePage())),
GoRoute(
name: 'login',
path: '/login',
pageBuilder: (context, state) => MaterialPage(
key: state.pageKey,
child: LoginPage(authRepo: auth,))),
],
errorPageBuilder: (context, state) => const MaterialPage(
child: Scaffold(
body: Center(
child: Text("404 Error"),
),
)));
runApp(MyApp(router: router,authRepo: auth,));
}
class MyApp extends StatelessWidget {
final GoRouter router;
final AuthRepo authRepo;
const MyApp({Key? key, required this.router, required this.authRepo}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationProvider: router.routeInformationProvider,
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
debugShowCheckedModeBanner: false,
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
PointerDeviceKind.mouse,
PointerDeviceKind.touch,
PointerDeviceKind.stylus,
PointerDeviceKind.unknown
},
),
title: 'CMS Prototype',
theme: appTheme,
);
}
}
auth repo class : ---->
class AuthRepo {
final AuthCache _cache;
final firebase_auth.FirebaseAuth _firebaseAuth;
final GoogleSignIn _googleSignIn;
AuthRepo({AuthCache? cache, firebase_auth.FirebaseAuth? firebaseAuth, GoogleSignIn? googleSignIn})
: _cache = cache?? AuthCache(),
_firebaseAuth = firebaseAuth ?? firebase_auth.FirebaseAuth.instance,
_googleSignIn = googleSignIn ?? GoogleSignIn.standard();
Stream<User> get user {
return _firebaseAuth.authStateChanges().map((fUser){
final user = fUser == null ? User.empty : fUser.toUser;
_cache.write(key: user.id, value: user);
return user;
});
}
User get currentUser {
final key = _firebaseAuth.currentUser != null? _firebaseAuth.currentUser!.uid : '';
return _cache.read(key: key) ?? User.empty;
}
Future<void> signUp({required String email, required String password}) async {
try {
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
} on firebase_auth.FirebaseAuthException catch (e) {
throw SignUpWithEmailAndPasswordFailure.fromCode(e.code);
} catch (_) {
throw const SignUpWithEmailAndPasswordFailure();
}
}
//login with google (GOOGLE SIGN IN)
Future<void> loginWithGoogle() async {
try {
late final firebase_auth.AuthCredential credential;
if(kIsWeb){
final googleProvider = firebase_auth.GoogleAuthProvider();
final userCredential = await _firebaseAuth.signInWithPopup(googleProvider);
credential = userCredential.credential!;
}else{
final googleUser = await _googleSignIn.signIn();
final googleAuth = await googleUser!.authentication;
credential = firebase_auth.GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken
);
}
await _firebaseAuth.signInWithCredential(credential);
}
on firebase_auth.FirebaseAuthException catch (e){
throw LogInWithGoogleFailure.fromCode(e.code);
}
catch (e){
throw const LogInWithGoogleFailure();
}
}
//email dan password
Future<LogInWithEmailAndPasswordFailure?> loginWithEmailAndPassword ({required String email, required String password}) async{
try{
await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password
);
}
on firebase_auth.FirebaseAuthException catch (e){
//return e.code;
return LogInWithEmailAndPasswordFailure.fromCode(e.code);
}
catch (_){
//return 'masalah jaringan terdeteksi';
return const LogInWithEmailAndPasswordFailure();
}
return null;
}
Future<void> logOut() async {
try {
await Future.wait([
_firebaseAuth.signOut(),
_googleSignIn.signOut(),
]);
} catch (_) {
throw LogOutFailure();
}
}
}
You should be able to access all the data for the current user using FirebaseAuth.instance.currentUser. Use that to access the current user and pass any data to backend using that user's credentials and token.
final user = FirebaseAuth.instance.currentUser;
I am creating custom dynamic link as given below:
Future<String> generateDynamicLink(
String pid, String imgurl, String title, String description) async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: uriPrefix,
link: Uri.parse(
uriPrefix+'/pd?pid=$pid',
),
androidParameters: AndroidParameters(
packageName: 'com.test',
minimumVersion: 0,
),
socialMetaTagParameters: SocialMetaTagParameters(
description: description,
imageUrl: Uri.parse(
imgurl,
),
title: title,
),
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.unguessable,
),
);
Uri url = await parameters.buildUrl();
ShortDynamicLink shortenedLink = await DynamicLinkParameters.shortenUrl(
url,
DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.unguessable),
);
return shortenedLink.shortUrl.toString();
}
And handling the receiving part by calling the fetchLinkData (see below) inside the initState of my home page
void fetchLinkData(BuildContext context) async {
var link = await FirebaseDynamicLinks.instance.getInitialLink();
handleLinkData(link, context);
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
handleLinkData(dynamicLink, context);
},
onError: (OnLinkErrorException error) async {
print(error.message);
},
);
}
void handleLinkData(PendingDynamicLinkData data, BuildContext context) async {
final Uri uri = data?.link;
if (uri != null) {
final queryParams = uri.queryParameters;
if (queryParams.keys.contains("pid")) {
String pid = queryParams["pid"];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductScreen(id: pid),
),
);
}
}
}
Now my problem is, On emulator everything works as expected and when the dynamic link is opened it navigates to the correct page but when I try on my android device only the app is opened.
If anyone else is having the same problem, removing the intent filter solved the problem for me.
i am using firebase dynamic link and it is working in google chrome , messenger , whatsapp but not working in facebook browser it is opening play store
my code to create dynamic link
Future<String> _createDynamicLink(id) async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: "http://applic.page.link",
link: Uri.parse("https://applic.page.link/heloo"),
androidParameters: AndroidParameters(
packageName: com.examole.myapp,
minimumVersion: 0,
),
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.short,
),
iosParameters: IosParameters(
bundleId: 'com.google.FirebaseCppDynamicLinksTestApp.dev',
minimumVersion: '0',
),
);
Uri url;
final ShortDynamicLink shortLink = await parameters.buildShortLink();
url = shortLink.shortUrl;
setState(() {
_linkMessage = url.toString();
});
return _linkMessage;
}
my code to fetch the link
void initDynamicLinks() async {
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HelooPage()));
}
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HelooPage()));
}
},
onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
}
i use flutter android studio
Can you please tell me how to Send and fetch the arguments using the flutter plugin firebase_dynamic_links[https://pub.dev/packages/firebase_dynamic_links#-readme-tab-]?
I want to pass parameters like username and password in the deeplink/dynamic link as follow :
uriPrefix: 'https://test.page.link/appinvite?username=Test&password=123456',
link: Uri.parse('https://test.page.link/appinvite?username=Test&password=123456'),
Is this the correct way to pass the data ?
After that i am using below code to fetch data,
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
But, it is providing me the dummy web URL i have added in the firebase console for firebase dynamic links in Deep Link URL
currently i am able to open the app from firebase dynamic link but, unable to fetch custom parameters.
Any help will be appreciated.
Updated Code :
For sending invite :
_generateAndShareDynamicLink() async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://test.page.link/groupinvite',
link: Uri.parse('https://test.page.link/groupinvite'),
androidParameters: AndroidParameters(
packageName: 'com.test.flutter_authentication',
minimumVersion: 0,
),
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.unguessable,
),
);
Uri url = await parameters.buildUrl();
shareURL(Uri.https(url.authority, url.path, {"username": "Test"}));
}
For fetching data inside initState() :
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text("deepLink2 : ${deepLink}",)));
if (deepLink != null) {
Map sharedListId = deepLink.queryParameters;
print("sharedListId : ${sharedListId}");
String username=sharedListId["username"];
print("username : ${username}");
Navigator.pushNamed(context, deepLink.path);
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
Still retrieved data is null.
Can anybody help ?
The best way to use dynamic links are,
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
#override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
#override
void initState() {
super.initState();
fetchLinkData();
}
void fetchLinkData() async {
// FirebaseDynamicLinks.getInitialLInk does a call to firebase to get us the real link because we have shortened it.
var link = await FirebaseDynamicLinks.instance.getInitialLink();
// This link may exist if the app was opened fresh so we'll want to handle it the same way onLink will.
handleLinkData(link);
// This will handle incoming links if the application is already opened
FirebaseDynamicLinks.instance.onLink(onSuccess: (PendingDynamicLinkData dynamicLink) async {
handleLinkData(dynamicLink);
});
}
void handleLinkData(PendingDynamicLinkData data) {
final Uri uri = data?.link;
if(uri != null) {
final queryParams = uri.queryParameters;
if(queryParams.length > 0) {
String userName = queryParams["username"];
// verify the username is parsed correctly
print("My users username is: $userName");
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample"),
),
body: Center(
child: Text("Test"),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
var dynamicLink = await createDynamicLink(userName: "Test");
// dynamicLink has been generated. share it with others to use it accordingly.
print("Dynamic Link: $dynamicLink");
},
child: Icon(
Icons.add,
color: Colors.white,
),
),
);
}
Future<Uri> createDynamicLink({#required String userName}) async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
// This should match firebase but without the username query param
uriPrefix: 'https://test.page.link',
// This can be whatever you want for the uri, https://yourapp.com/groupinvite?username=$userName
link: Uri.parse('https://test.page.link/groupinvite?username=$userName'),
androidParameters: AndroidParameters(
packageName: 'com.test.demo',
minimumVersion: 1,
),
iosParameters: IosParameters(
bundleId: 'com.test.demo',
minimumVersion: '1',
appStoreId: '',
),
);
final link = await parameters.buildUrl();
final ShortDynamicLink shortenedLink = await DynamicLinkParameters.shortenUrl(
link,
DynamicLinkParametersOptions(shortDynamicLinkPathLength: ShortDynamicLinkPathLength.unguessable),
);
return shortenedLink.shortUrl;
}
}
You're done.
This worked for me
The sending side:
Future<String> generateLink() async {
final DynamicLinkParameters parameters = DynamicLinkParameters(
uriPrefix: 'https://<your-domain-name>.page.link',
link: Uri.parse(
'https://<your-domain-name>.page.link/<your-route>/?id=acb&name=me'), // <- your paramaters
dynamicLinkParametersOptions: DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.unguessable),
androidParameters: AndroidParameters(
packageName: '<package-name>',
minimumVersion: 0,
),
socialMetaTagParameters: SocialMetaTagParameters(
title: "click the link",
),
);
final Uri dynamicUrl = await parameters.buildUrl();
final ShortDynamicLink shortenedLink =
await DynamicLinkParameters.shortenUrl(
dynamicUrl,
DynamicLinkParametersOptions(
shortDynamicLinkPathLength: ShortDynamicLinkPathLength.unguessable),
);
final Uri shortUrl = shortenedLink.shortUrl;
return "https://<your-domain-name>.page.link" + shortUrl.path;
}
The receiving side:
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
print(deepLink.queryParameters['id']); // <- prints 'abc'
}
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
}
);
I make a program to save photo in the Firebase Storage and then take a url and write it to the Firebase database.
File sampleImage;
String changePhoto;
Future getImage() async {
var tempImage = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
sampleImage = tempImage;
});
}
Future getUrl(name) async
{
final ref = FirebaseStorage.instance.ref().child(name);
changePhoto = await ref.getDownloadURL();
print(changePhoto);
return changePhoto;
}
Widget submitButton() {
final name = productName.text;
return RaisedButton(
textColor: Colors.white,
color: Color(0xffd50000),
child: Text("Add"),
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
onPressed: () {
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child(name);
final StorageUploadTask task =
firebaseStorageRef.putFile(sampleImage);
getUrl(name);
_bloc.submit(changePhoto);
print(5);
Navigator.of(context).pop();
});
}
But i have problem with
changePhoto = await ref.getDownloadURL();
because ref.getDownloadURL() returns a dynamic variable. I tried to use
Future loadPhoto(name)
{
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child(name);
final StorageUploadTask task =
firebaseStorageRef.putFile(sampleImage);
}
onPressed: () {
loadPhoto(name).then((snapshot){
final ref = FirebaseStorage.instance.ref().child(name);
changePhoto = snapshot.ref.getDownloadURL();
print(changePhoto);
_bloc.submit(changePhoto);
print(5);
Navigator.of(context).pop();
});
But it doesn't work. What is my mistake or how I can get snapshot?
Any help is much appreciated.
Wait to finish upload process like;
var dowurl = await (await uploadTask.onComplete).ref.getDownloadURL();