Apple sign in plugin for flutter app

Hi,

I am not able to find any documents related integrating apple sign in for flutter app with backendless service. Can anyone advise?

Hello, @CHEONG_YEW_HOONG.

Are you using backendless-sdk for flutter, or ui builder packaged in native shell with flutter?

Best Regards, Nikita.

Hi @Nikita_Fedorishchev ,

I am using backendless-sdk for flutter.

  1. You need to integrate “Login with Apple” service from Marketplace into your app.
    Follow “Installation Instructions” here.

  2. Then you need to add sign_in_with_apple: ^3.3.0 dependency into your pubspec.yaml file.

  3. And with this code you can login via apple:

           final credential = await SignInWithApple.getAppleIDCredential(
               scopes: [
                 AppleIDAuthorizationScopes.email,
                 AppleIDAuthorizationScopes.fullName,
               ],
               webAuthenticationOptions: WebAuthenticationOptions(
                 clientId: 'paste your clientId here',
                 redirectUri: Uri(),
               ));
           result = await Backendless.customService.invoke('AppleAuth',
               'login', credential.identityToken); //get your user
           result = BackendlessUser.fromJson(result);
    

Do not forget to add apple sign-in into xcode project.
Best Regards, Nikita.

1 Like

Hi @Nikita_Fedorishchev ,

I am facing an issue that the InitApp not able to check the logged in user that using apple login method. Thus, i have failed to stay log in the user. However, this InitApp works with username/password login method.

Anyway, i am able to register the user using apple sign in method and i can see the user created in backendless user database.

class InitApp {
  static final String apiKeyAndroid = 'XXXXXXXX';
  static final String apiKeyiOS = 'XXXXXXXX';
  static final String appID = 'XXXXXXXX';

  static void initializeApp(BuildContext context) async {
    await Backendless.initApp(
        applicationId: appID,
        iosApiKey: apiKeyiOS,
        androidApiKey: apiKeyAndroid);

    String result = await context.read<UserService>().checkIfUserLoggedIn();
    if (result == 'OK') {
      Navigator.pushNamedAndRemoveUntil(
          context, '/splash1Page', (route) => false);
    } else {
      //Navigator.popAndPushNamed(context, RouteManager.loginPage);
      Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false);
    }
  }
}
  Future<String> checkIfUserLoggedIn() async {
    String result = 'OK';

    bool? validLogin = await Backendless.userService
        .isValidLogin()
        .onError((error, stackTrace) {
      result = error.toString();
    });

    if (validLogin != null && validLogin) {
      String? currentUserObjectId = await Backendless.userService
          .loggedInUser()
          .onError((error, stackTrace) {
        result = error.toString();
      });
      if (currentUserObjectId != null) {
        Map<dynamic, dynamic>? mapOfCurrentUser = await Backendless.data
            .of("Users")
            .findById(currentUserObjectId)
            .onError((error, stackTrace) {
          result = error.toString();
        });
        if (mapOfCurrentUser != null) {
          _currentUser = BackendlessUser.fromJson(mapOfCurrentUser);
          globals.userId = _currentUser?.getUserId();
          globals.userEmail = _currentUser?.email;
          print(globals.userId.toString() + globals.userEmail.toString());
          notifyListeners();
        } else {
          removeTokenAndData();
          result = 'NOT OK';
        }
      } else {
        removeTokenAndData();
        result = 'NOT OK';
      }
    } else {
      removeTokenAndData();
      result = 'NOT OK';
    }

    return result;
  }

Can i have your advise please?

Hello, @CHEONG_YEW_HOONG.

Try to use the setCurrentUser method after Apple login.

Best Regards, Nikita

Hi @Nikita_Fedorishchev ,

Unfortunately, setCurrentUser didn’t work either.

      var appleAuth = await Backendless.customService
          .invoke('AppleAuth', 'login', appleIdCredential.identityToken);
      appleAuth = BackendlessUser.fromJson(appleAuth);
      print(appleAuth);

      **Backendless.userService.setCurrentUser(appleAuth);**

Hello, @CHEONG_YEW_HOONG.

I will try to do it and answer you.

Best Regards, Nikita.

I found a problem with the setCurrentUser method. I’ll let you know when it’s fixed.

Best Regards, Nikita.

Problem was fixed. You need to use last version of backendless_sdk(7.2.6).
This code works:

                  var result;
                  final credential = await SignInWithApple.getAppleIDCredential(
                      scopes: [
                        AppleIDAuthorizationScopes.email,
                        AppleIDAuthorizationScopes.fullName,
                      ],
                      webAuthenticationOptions: WebAuthenticationOptions(
                        clientId: 'your clientId',
                        redirectUri: Uri(),
                      ));
                  result = await Backendless.customService.invoke('AppleAuth',
                      'login', credential.identityToken); //get your user

                  result = BackendlessUser.fromJson(result);
                  await Backendless.userService
                      .setCurrentUser(result, stayLoggedIn: true);

Best Regards, Nikita.

Hi @Nikita_Fedorishchev ,

Thanks for updating the sdk(7.2.6). However, the outcome is the same. InitApp not able to detect logged in user(if using apple sign in) and navigated to login page…

Hello, @CHEONG_YEW_HOONG.

Can you share your code with me?

Best Regards, Nikita.

Hi @Nikita_Fedorishchev,

apple login function:

Future<void> appleSignIn(BuildContext context) async {
  try {
    final appleIdCredential = await SignInWithApple.getAppleIDCredential(
      scopes: [
        AppleIDAuthorizationScopes.email,
        AppleIDAuthorizationScopes.fullName,
      ],
    );
    if (appleIdCredential != null) {
      var appleAuth = await Backendless.customService
          .invoke('AppleAuth', 'login', appleIdCredential.identityToken);
      appleAuth = BackendlessUser.fromJson(appleAuth);
      await Backendless.userService
          .setCurrentUser(appleAuth, stayLoggedIn: true);
      Navigator.of(context).popAndPushNamed(RouteManager.splash2Page);
    } else {
      const snackBar = SnackBar(content: Text("Not able to sign in"));
      ScaffoldMessenger.of(context).showSnackBar(snackBar);
    }
  } catch (e) {
    final snackBar = SnackBar(content: Text(e.toString()));
    ScaffoldMessenger.of(context).showSnackBar(snackBar);
  }
}

InitApp function:

class InitApp {
  static const String apiKeyAndroid = 'XXXXXXXX';
  static const String apiKeyiOS = 'XXXXXXXX';
  static const String appID = 'XXXXXXXX';

  static void initializeApp(BuildContext context) async {
    await Backendless.initApp(
        applicationId: appID,
        iosApiKey: apiKeyiOS,
        androidApiKey: apiKeyAndroid);

    String result = await context.read<UserService>().checkIfUserLoggedIn();
    if (result == 'OK') {
      Navigator.pushNamedAndRemoveUntil(
          context, '/splash1Page', (route) => false);
    } else {
      Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false);
    }
  }
}

check user logged in function:

  Future<String> checkIfUserLoggedIn() async {
    String result = 'OK';

    bool? validLogin = await Backendless.userService
        .isValidLogin()
        .onError((error, stackTrace) {
      result = error.toString();
    });

    if (validLogin != null && validLogin) {
      String? currentUserObjectId = await Backendless.userService
          .loggedInUser()
          .onError((error, stackTrace) {
        result = error.toString();
      });
      if (currentUserObjectId != null) {
        Map<dynamic, dynamic>? mapOfCurrentUser = await Backendless.data
            .of("Users")
            .findById(currentUserObjectId)
            .onError((error, stackTrace) {
          result = error.toString();
        });
        if (mapOfCurrentUser != null) {
          _currentUser = BackendlessUser.fromJson(mapOfCurrentUser);
          notifyListeners();
        } else {
          removeTokenAndData();
          result = 'NOT OK';
        }
      } else {
        removeTokenAndData();
        result = 'NOT OK';
      }
    } else {
      removeTokenAndData();
      result = 'NOT OK';
    }

    return result;
  }

The bool? validLogin always return as false after reopen the app while logged in using apple sign in.

With a default login, everything works as it should?

Hi @Nikita_Fedorishchev,

Yes. I have no problem with login using email and password.

I have already reproduced the problem, we are working on a solution(isValidLogin seems broken after using setCurrentUser).

Hi @Nikita_Fedorishchev,

Good day. Any update regarding this issue?

Hi, @CHEONG_YEW_HOONG

We have an internal ticket on this issue - BKNDLSS-30041. Our developer will take a look at it more closely. Stay tuned, we will reply to you in this thread when have more information about the problem.

Regards,
Marina

Resolved in new version of Flutter-sdk(8.0.0).