The named parameter '~' isn't defined - flutter

I'm flutter beginner. I'm using local-auth for making Bio auth function. but error like below, I don't get the error why it occurs. Could you advice for this? why is it doesn't work in authenticate(), useErrorDialogs, stickyAuth, biometricOnly those three objects occurs error?
class AuthService {
static Future<bool> authenticate({
String localizedReason,
bool useErrorDialogs,
bool stickyAuth,
bool biometricOnly ,
}) {
// TODO: implement authenticate
throw UnimplementedError();
}
static Future<bool> authenticateUser() async {
//initialize Local Authentication plugin.
final LocalAuthentication _localAuthentication = LocalAuthentication();
//status of authentication.
bool isAuthenticated = false;
//check if device supports biometrics authentication.
bool isBiometricSupported = await _localAuthentication.isDeviceSupported();
//check if user has enabled biometrics.
//check
bool canCheckBiometrics = await _localAuthentication.canCheckBiometrics;
//if device supports biometrics and user has enabled biometrics, then authenticate.
if (isBiometricSupported && canCheckBiometrics) {
try {
isAuthenticated = await _localAuthentication.authenticate(
localizedReason: 'Scan your fingerprint to authenticate',
useErrorDialogs: true,
stickyAuth: true,
biometricOnly: true,
);
} on PlatformException catch (e) {
print(e);
}
}
return isAuthenticated;
}
}

Related

Why currentUser is null while isSignedIn works perfect in Flutter

I implemented google signIn in Provider pattern, the signIn, signOut and isSignedIn work perfectly but currentUser is always null. Why?
class LoginController with ChangeNotifier {
var _googleSignIn = GoogleSignIn(scopes: [
'email'
]);
GoogleSignInAccount? get currentUser {
return _googleSignIn.currentUser;
}
Future<GoogleSignInAccount?> signIn() async {
try {
_googleSignIn.signIn();
} catch (e) {
print(e);
}
}
And in UI I use:
var user = Provider.of<LoginController>(context, listen: false).currentUser;
bool isSignedIn = await Provider.of<LoginController>(context,listen: false).isSignedIn();
Try setting listen: true to enable a rebuild on the widget when currentUser is set:
var user = Provider.of<LoginController>(context, listen: true).currentUser;
print("user is " + (user == null ? "not set" : "set"));

how to check if getLogin() function worked or not to display login was successful or not

I am not understanding how do i check if getLogin() function worked or not and if user exists or not.
where do i write the code to display the message. When I checked by assigning a variable to this statement
res=dbService.getLogin(_email, _password); then it shows datatype mismatch. Can u plzz help me with this. I am developing flutter app in android studio and using sqlite. Please do help me I am stuck from 2 days.
I call _submit() on login button
bool validateAndSave() {
final form = _formKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
void _submit(){
if (validateAndSave()) {
setState(() {
dbService.getLogin(_email, _password);
});
}
}
And this is db_service.dart code for getLogin()
Future<RegisterUser> getLogin(String user, String password) async {
await DB.init();
var res = await DB.rawQuery("userDetails WHERE emailId = '$user' and password = '$password'");
if (res.length > 0) {
return RegisterUser.fromMap(res.first);
}
return null;
}
You could wait for the result of the login method.
void _submit() async {
if (validateAndSave()) {
var user = await dbService.getLogin(_email, _password);
if (user != null) {
Navigator.of(context).pushNamed('/home');
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("Sign in error")));
}
}
}
In this case I pushed to the home screen if successfull and showed a snackbar in case of error. You could adjust this to your intended use case.

Flutter | Getting Firebase Email Link Login Data

I have difficulty implementing the Email Link login with Firebase.
I send the email link using:
_firebaseAuth.sendSignInLinkToEmail(
email: email,
actionCodeSettings: ActionCodeSettings(
url: 'https://subdomain.example.com/user-auth', //<subdomain.example.com> = my real domain
handleCodeInApp: true,
androidInstallApp: true,
androidPackageName: 'com.example.app',
),
);
Email is sent and when clicking I open the link using the DynamicLink package:
void _handleDynamicLinks() {
FirebaseDynamicLinks.instance.onLink(onSuccess: _onSuccess);
}
Future<dynamic> _onSuccess(PendingDynamicLinkData data) async {
print('---onLink---');
// How to pass signIn link to `isSignInWithEmailLink` and `signInWithEmailLink` ???
// data.link returns `https://subdomain.example.com/user-auth` which is not the complete link
}
Every method I call on PendingDynamicLinkData data doesn't return the full dynamic link and isSignInWithEmailLink returns false!
Try this in your _handleDynamicLink function.
try {
FirebaseDynamicLinks.instance.onLink.listen((dynamicLink) {
final Uri? deepLink = dynamicLink.link;
if (deepLink != null) {
emailLinkService.handleLink(deepLink, _emailController.text);
FirebaseDynamicLinks.instance.onLink.listen((dynamicLink) {
final Uri? deepLink = dynamicLink.link;
emailLinkService.handleLink(deepLink!, _emailController.text);
}, onError: (e) async {
print(e.message);
});
}
}, onError: (e) async {
print(e.message);
});
final PendingDynamicLinkData? data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri? deepLink = data?.link;
print('deepLink :: $deepLink');
} catch (e) {
// you can print this error as well
}
And check if your url is the same as here:
And also add the Dynamic link as your custom Authorised domain like this:
Here is the handleLink method:
class EmailLinkService {
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<void> signInWithEmailAndLink(
{required String userEmail}) async {
var _userEmail = userEmail;
var acs = ActionCodeSettings(
url: Constants.firebaseProjectURL,
handleCodeInApp: true,
iOSBundleId: 'com.example....',
androidPackageName: 'com.example....',
try {
return await _auth
.sendSignInLinkToEmail(email: _userEmail, actionCodeSettings: acs);
} on FirebaseAuthException catch (e) {
}
void handleLink(Uri link, userEmail) async {
if (link != null) {
final UserCredential user =
await FirebaseAuth.instance.signInWithEmailLink(
email: userEmail,
emailLink: link.toString(),
);
} else {
print(" link is null");
}
}
}

Flutter api login using riverpod

I'm trying to use riverpod for login with a laravel backend. Right now I'm just returning true or false from the repository. I've set a form that accepts email and password. The isLoading variable is just to show a circle indicator. I've run the code and it works but not sure if I'm using riverpod correctly. Is there a better way to do it ?
auth_provider.dart
class Auth{
final bool isLogin;
Auth(this.isLogin);
}
class AuthNotifier extends StateNotifier<Auth>{
AuthNotifier() : super(Auth(false));
void isLogin(bool data){
state = new Auth(data);
}
}
final authProvider = StateNotifierProvider((ref) => new AuthNotifier());
auth_repository.dart
class AuthRepository{
static String url = "http://10.0.2.2:8000/api/";
final Dio _dio = Dio();
Future<bool> login(data) async {
try {
Response response = await _dio.post(url+'sanctum/token',data:json.encode(data));
return true;
} catch (error) {
return false;
}
}
}
login_screen.dart
void login() async{
if(formKey.currentState.validate()){
setState((){this.isLoading = true;});
var data = {
'email':this.email,
'password':this.password,
'device_name':'mobile_phone'
};
var result = await AuthRepository().login(data);
if(result){
context.read(authProvider).isLogin(true);
setState((){this.isLoading = false;});
}else
setState((){this.isLoading = false;});
}
}
Since I'm not coming from mobile background and just recently use flutter+riverpod in my recent project, I cannot say this is the best practice. But there are some points I'd like to note:
Use interface such IAuthRepository for repository. Riverpod can act as a dependency injection.
final authRepository = Provider<IAuthRepository>((ref) => AuthRepository());
Build data to send in repository. You should separate presentation, business logic, and explicit implementation for external resource if possible.
Future<bool> login(String email, String password) async {
try {
var data = {
'email': email,
'password': password,
'device_name':'mobile_phone'
};
Response response = await _dio.post(url+'sanctum/token',data:json.encode(data));
return true;
} catch (error) {
return false;
}
}
Do not call repository directly from presentation/screen. You can use the provider for your logic, which call the repository
class AuthNotifier extends StateNotifier<Auth>{
final ProviderReference ref;
IAuthRepository _authRepository;
AuthNotifier(this.ref) : super(Auth(false)) {
_authRepository = ref.watch(authRepository);
}
Future<void> login(String email, String password) async {
final loginResult = await_authRepository.login(email, password);
state = Auth(loginResult);
}
}
final authProvider = StateNotifierProvider((ref) => new AuthNotifier(ref));
On screen, you can call provider's login method
login() {
context.read(authProvider).login(this.email, this.password);
}
Use Consumer or ConsumerWidget to watch the state and decide what to build.
It also helps that instead of Auth with isLogin for the state, you can create some other state. At the very least, I usually create an abstract BaseAuthState, which derives to AuthInitialState, AuthLoadingState, AuthLoginState, AuthErrorState, etc.
class AuthNotifier extends StateNotifier<BaseAuthState>{
...
AuthNotifier(this.ref) : super(AuthInitialState()) { ... }
...
}
Consumer(builder: (context, watch, child) {
final state = watch(authProvider.state);
if (state is AuthLoginState) ...
else if (state is AuthLoadingState) ...
...
})
Instead of using a bool, I like to use enums or class for auth state
enum AuthState { initialize, authenticated, unauthenticated }
and for login state
enum LoginStatus { initialize, loading, success, failed }

Flutter Pin/Password/Pattern Integration

I have went through the local_auth package and it works fine, but it does not have an option to authenticate with password or pin. Help appreciated!
String _authorized = 'Not Authorized';//Start
Future<Null> _authenticate() async {
final LocalAuthentication auth = new LocalAuthentication();
bool authenticated = false;
try {
authenticated = await auth.authenticateWithBiometrics(
localizedReason: 'Scan your fingerprint to authenticate',
useErrorDialogs: true,
stickyAuth: false);
authenticated = await auth.authenticateWithBiometrics(localizedReason: 'Authenticate');
} on PlatformException catch (e) {
print(e);
}
if (!mounted) return;
setState(() {
_authorized = authenticated ? 'Authorized' : 'Not Authorized';
});
}//End
So this is the example code and you can use biometric authentication but what about the default Pin/Password authentication that is also present with fingerprint.
For security reason, mobile (iOS/Android) will only authenticate user by biometrics, not system password/pin. If you want to let user authenticate by other methods than biometrics, the app itself must store and process (encrypted) credential which is totally separated from system password/pin.
You can see this behavior (to use system-biometrics AND app-specific credential) in many bank/financial related app, such as https://play.google.com/store/apps/details?id=com.konylabs.capitalone&hl=en