alternate method of onRequestPermissionResult() in Flutter - flutter

I am requesting runtime permissions in Flutter. How to handle the result of permissions in Flutter. As we know In Android there is onRequestPermissionsResult(). Whats alternate method in Flutter.

use the plugin simple_permissions
It can check, request and get permissions with callbacks
Sample code from the example
requestPermission() async {
final res = await SimplePermissions.requestPermission(permission);
print("permission request result is " + res.toString());
}
checkPermission() async {
bool res = await SimplePermissions.checkPermission(permission);
print("permission is " + res.toString());
}
getPermissionStatus() async {
final res = await SimplePermissions.getPermissionStatus(permission);
print("permission status is " + res.toString());
}

Related

How to request refresh token called once on multiple api calls

I have a function that refreshes a token if the previous API response returns an error code of 1000. However, when multiple API calls are made at the same time, it results in multiple refresh token requests. I want to ensure that the refresh token is only called once.
Here is my code
requestGet(String endPoint, Map<String, dynamic> params, [bool isUsingToken = false]) async {
String sign = getSign(timestamp + jsonEncode(params));
String deviceId = await SharedPrefsService().getDeviceId();
String token = await SharedPrefsService().getToken();;
final response = await httpGet(endPoint, params, sign, token, deviceId, isUsingToken);
dynamic result = response;
var isRenewed = await renewTokenIfNeeded(deviceId, result, endPoint);
if (isRenewed) {
token = await SharedPrefsService().getToken();
final renewedResponse = await httpGet(endPoint, params, sign, token, deviceId, isUsingToken);
result = renewedResponse;
}
return result;
}
Future<bool> renewTokenIfNeeded(String deviceId, result) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool renewingToken = prefs.getBool('renewingToken') ?? false;
if (result['error_code'] == '1000') {
prefs.setBool('renewingToken', true);
try {
if (renewingToken) {
return true;
}
var isRenewed = await requestRenewToken(deviceId);
if (isRenewed) {
prefs.setBool('renewingToken', false);
return true;
}
} finally {
prefs.setBool('renewingToken', false);
}
}
return false;
}
requestRenewToken(String deviceId) async {
var refresh = await AuthenticationService().refreshToken();
if (refresh.errorCode == '9999') {
SharedPrefsService().clearAllData();
return false; // then back to sign in
}
if (refresh.errorCode == '0000') {
SharedPrefsService().saveTokenData(refresh.token!, refresh.userName!, deviceId);
return true;
}
return false;
}
I have tried using synchronized and mutex packages, but they do not seem to work and I prefer to minimize the use of external packages. Can you please suggest a solution? Thank you!

flutter dio(4.0.0) handling token expiration (handling 401)

I have declared a class to make api requests using flutter Dio as follows.
class DioUtil {
static Dio _instance;
static Dio getInstance() {
if (_instance == null) {
_instance = createDio();
}
return _instance;
}
static Dio createDio() {
var dio = Dio();
dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
// Do something before request is sent
return handler.next(options); //continue
}, onResponse: (response, handler) {
// Do something with response data
return handler.next(response); // continue
}, onError: (DioError e, handler) async {
if (e.response != null) {
if (e.response.statusCode == 401) {
var dio = DioUtil.getInstance();
dio.interceptors.requestLock.lock();
dio.interceptors.responseLock.lock();
RequestOptions requestOptions = e.requestOptions;
await refreshToken();
Repository repository = Repository();
var accessToken = await repository.readData("accessToken");
final opts = new Options(
method: requestOptions.method
);
dio.options.headers["Authorization"] = "Bearer " + accessToken;
dio.interceptors.requestLock.unlock();
dio.interceptors.responseLock.unlock();
dio.request(requestOptions.path,
options: opts,
data: requestOptions.data,
queryParameters: requestOptions.queryParameters);
}//TODO: handle else clause
}
}));
return dio;
}
static refreshToken() async {
Response response;
Repository repository = Repository();
var dio = Dio();
final Uri apiUrl = Uri.parse(BASE_PATH + "auth/reIssueAccessToken");
var refreshToken = await repository.readData("refreshToken");
dio.options.headers["Authorization"] = "Bearer " + refreshToken;
response = await dio.postUri(apiUrl);
if (response.statusCode == 200) {
LoginResponse loginResponse =
LoginResponse.fromJson(jsonDecode(response.toString()));
repository.addValue('accessToken', loginResponse.data.accessToken);
repository.addValue('refreshToken', loginResponse.data.refreshToken);
} else {
print(response.toString());
}
}
}
and I use flutter bloc pattern and my bloc is as follows.
class OurClassBloc extends Bloc<OurClassEvent, OurClassState> {
OurClassBloc(OurClassState initialState) : super(initialState);
Repository repository = Repository();
#override
Stream<OurClassState> mapEventToState(
OurClassEvent event,
) async* {
if (event is GetClasses) {
yield* _getClassCategories(event);
}
}
Stream<OurClassState> _getClassCategories(GetClasses event) async* {
Response response;
var dio = DioUtil.getInstance();
final String apiUrl = (BASE_PATH + "classCategories");
var accessToken = await repository.readData("accessToken");
Map<String, dynamic> map = {"active": event.active};
dio.options.headers["Authorization"] = "Bearer " + accessToken;
dio.options.headers["Accept"] = "*/*";
try {
response = await dio.get(apiUrl, queryParameters: map);
if (response.statusCode == 200) {
OurClassResponse loginResponse =
OurClassResponse.fromJson(jsonDecode(response.toString()));
yield OurClassSuccess(loginResponse);
}
if (response.statusCode >= 400) {
yield OurClassFailed();
}
} catch (e) {
yield OurClassFailed();
}
}
}
When I make the requests with valid access token, I get 200 status code in bloc class and api works fine.when the token is expired, the dio class correctly gets the new token, make the same api call with new token successfully and inside the below callback I get the correct response also.
onResponse: (response, handler) {
return handler.next(response);
}
but response doesn't comes to bloc class. Though it returned the response by calling return handler.next(response);,it is not coming to response variable inside _getClassCategories method.I expect the correct response should come to the response variable in bloc class for both scenarios:
makes the api call with valid token.
makes the api call with expired token.
but only scenario 1 is working in my code and hope someone here can help me to fix this.
EDIT- this works fine with dio previous version(3.0.10) - code
dio.request(requestOptions.path,
options: opts,
data: requestOptions.data,
queryParameters: requestOptions.queryParameters);
This line creates a new request with no relation to the original one. If the request succeeds, there is no code listening for a response. If you want the original caller to receive anything, you will need to forward the response to the original handler:
try {
final response = await dio.request(requestOptions.path,
options: opts,
data: requestOptions.data,
queryParameters: requestOptions.queryParameters);
handler.resolve(response);
} on DioError catch (error) {
handler.next(error); // or handler.reject(error);
}
Also, be sure to forward the error to the handler in non-401 cases as well. Dio 4.0.0 interceptors don't automatically forward anything.

How to SignIn with google on Parse Server

I'm developing an application with Flutter and Parse Server and I want to register Users from google account.
I have tried:
static Future<void> loginWithGoogle() async {
try {
final _googleSignIn = GoogleSignIn(scopes: ['email', 'https://www.googleapis.com/auth/contacts.readonly']);
final account = await _googleSignIn.signIn(); // I figure out that the real error is here;
final authentication = await account.authentication;
final googleAuth = google(_googleSignIn.currentUser.id, authentication.accessToken, authentication.idToken);
final response = await ParseUser.loginWith('google', googleAuth);
if (response.success) {
print(response);
//currentUser = await ParseUser.currentUser(customUserObject: User.clone());
//Get.offNamed('/oauth');
}
} catch (e) {
print(e);
AlertUtils.showErrorDialog(e.toString());
}
}
but here I faced that error:
plugin: PlatformException(sign_in_failed,
com.google.android.gms.common.api.ApiException: 10: , null)
You cannot do this without registering on Firebase. The official documentation says so.

Google Authentication and Facebook Authentication Existing User

Hello Everyone someone please offer me some help if you can. I'm not sure if this is an issue on Firebase's side or if I failed on my code or configuring the Firebase authentication correctly.
So here's the issue.
I wanted to see if a user existed inside the firestore. If it does then link the accounts. I read the documentation and understand that when using the SigninwithCredential() it should throw an error saying something on the lines of "ERROR USER ALREADY EXISTS IN FIRESTORE".
So testing went something like this to see if I'd get an error before trying to handle the error.
Continue with Facebook (OK).
Signed In (OK).
Continue with Google (Expected Error) (Didn't throw Error)
So what happened here instead was the user originally created by Facebook was overridden by Google.
Sign In with Facebook (Expected Error) (OK) Recieved error as expected "An Account already exists but with different sign-in credentials"
Read documentation several times and compared google code with Facebook code and can't seem to find answer.
class MyFirebase {
static bool isSignIn = false;
static auth.FirebaseAuth _auth = auth.FirebaseAuth.instance;
static FacebookLogin facebookLogin = FacebookLogin();
static GoogleSignIn googleSignIn = GoogleSignIn();
static Future<auth.User> loginGoogle() async {
final prefs = await SharedPreferences.getInstance();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
if (googleSignInAccount == null) {
print("ERROR HAS OCCURED WITH THE GOOGLE LOGIN");
throw new Exception("ERROR HAS OCCURED WITH THE LOGIN");
} else {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
var item = googleSignInAccount.photoUrl;
print("PHOTO URL" + item);
prefs.setString("photoURL", item);
final auth.AuthCredential credential = auth.GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken);
try {
var authResult = await _auth.signInWithCredential(credential);
return authResult.user;
} catch (e) {
print(e);
throw (e);
}
}
}
static Future<auth.User> loginFacebook() async {
final FacebookLoginResult result = await facebookLogin.logIn(['email']);
final prefs = await SharedPreferences.getInstance();
var a;
switch (result.status) {
case FacebookLoginStatus.cancelledByUser:
print("CANCELLED BY USER DO NOT RETURN");
throw new Exception("CANCELLED BY USER DO NOT RETURN");
break;
case FacebookLoginStatus.error:
print("ERROR OCCURED");
throw new Exception("ERROR oCCURED");
break;
case FacebookLoginStatus.loggedIn:
try {
final FacebookAccessToken accessToken = result.accessToken;
auth.AuthCredential credential =
auth.FacebookAuthProvider.credential(accessToken.token);
print("########## MAKING GRAPH RESPONSE");
final response = await http.get(
'https://graph.facebook.com/v2.12/me?fields=name,first_name,picture.width(800).height(800),last_name,email&access_token=${accessToken.token}');
final profile = jsonDecode(response.body);
String item = profile['picture']['data']['url'];
prefs.setString("photoURL", item);
a = await _auth.signInWithCredential(credential);
return a.user;
} catch (e) {
print(e);
throw e;
}
break;
}
return null;
}
static Future<void> signOut() async {
await facebookLogin.logOut();
await _auth.signOut();
await googleSignIn.signOut();
}
}
**strong text** ```

Fetching Current Location with Permission not working

I am using
geolocator: '^3.0.1'
permission_handler: '^3.0.0'
Now I want to fetch the current location of the user and show it on the map as the user opens the Map.
So my Code is :
Future<void> requestPermission() async {
PermissionHandler()
.checkPermissionStatus(PermissionGroup.location)
.then((PermissionStatus permissionStatus) async {
print("Checking Permission " + permissionStatus.toString());
if (permissionStatus == PermissionStatus.granted) {
_getCurrentLocation();
} else {
print("Asking Permission " + permissionStatus.toString());
final List<PermissionGroup> permissions = <PermissionGroup>[
PermissionGroup.locationWhenInUse
];
final Map<PermissionGroup, PermissionStatus> permissionRequestResult =
await PermissionHandler().requestPermissions(permissions);
if (PermissionStatus.granted ==
permissionRequestResult[PermissionGroup.locationWhenInUse]) {
print("Permission Granted " + permissionStatus.toString());
_getCurrentLocation();
}
}
});
}
and permissions are defined in the manifest for android and info.list for IOS.
Now the issue is when I run this function and when it calls requestPermission function, it shows the popup asking for the permission and
when I allow the permission app crashes with an error :
java.lang.RuntimeException: Failure delivering result ResultInfo{who=#android:requestPermissions: ... java.lang.IllegalStateException: Reply already submitted
and also the result of permission is Permission.disabled though I allowed the permission in application settings and in permission it shows that location is permission is allowed. but I tried opening app several times it shows Permission.disabled.
and even if I deny the app crashes with the same error.
So what I have concluded is :
If I allow or deny it crashes because it is requesting multiple times and even if I allow the result is Permission.disabled.
Link for the video: https://youtu.be/A1DKkw6u4HI
Can anyone help me solving this issue?
Or please tell me how to take the current location map easily
please tell me how to take the current location map easily
If you just need to fetch current location easily and you just need location permission then :
you can use location plugin with flutter :
In your pubspec.yml : location : ^2.3.0
Then for fetching Current location :
Import location Package
import 'package:location/location.dart' as locationPackage;
Add this to your State
locationPackage.Location _locationService = new locationPackage.Location();
bool _permission = false;
Call this function in initState or whenever you need current Location
fetchCurrentLocation() async {
await _locationService.changeSettings(
accuracy: locationPackage.LocationAccuracy.HIGH, interval: 1000);
locationPackage.LocationData location;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
bool serviceStatus = await _locationService.serviceEnabled();
print("Service status: $serviceStatus");
if (serviceStatus) {
_permission = await _locationService.requestPermission();
print("Permission: $_permission");
if (_permission) {
location = await _locationService.getLocation();
print("Location: ${location.latitude}");
}
} else {
bool serviceStatusResult = await _locationService.requestService();
print("Service status activated after request: $serviceStatusResult");
if (serviceStatusResult) {
fetchCurrentLocation();
}
}
} on PlatformException catch (e) {
print(e);
if (e.code == 'PERMISSION_DENIED') {
//error = e.message;
} else if (e.code == 'SERVICE_STATUS_ERROR') {
//error = e.message;
}
location = null;
}
}