2

I am using LibGDX with RoboPods under Android Studio to compile for iOS. Having migrated from RoboVM to mobidevelop I am now facing some issues. The main one is that I cannot log onto Google.

I get the following error:

[GPGManager signIn:didSignInForUser:withError:]:[main] FAILED LOGGING INTO GOOGLE PLUS GAMES Error Domain=com.google.GIDSignIn Code=-2 "keychain error" UserInfo={NSLocalizedDescription=keychain error} 

Xcode version 8.2 Android Studio I am using version 4.0.0 of Google Sign-In SDK for iOS https://developers.google.com/identity/sign-in/ios/sdk/

I understand that you can change your KeyChain parameter within XCode, but as this is a LibGDX game I don't use XCode.

A sample project illustrating the issue is on githiub here: https://github.com/julienvillegas/LibGDX-Google-Play-Game-Services-Integration-Sample

My code is as follow:

import com.badlogic.gdx.Screen;
import com.badlogic.gdx.backends.iosrobovm.IOSApplication;
import com.badlogic.gdx.backends.iosrobovm.IOSApplicationConfiguration;
import com.julienvillegas.CrosswordParty.CrosswordParty;
import com.julienvillegas.CrosswordParty.NearbyGPGSPlayers;
import com.julienvillegas.GameWorld.CrosswordCommon.CrosswordGiftCreate.GiftGridCombinations;
import com.julienvillegas.GameWorld.Global;
import com.julienvillegas.actionResolver.ActionResolver;

import org.robovm.apple.foundation.Foundation;
import org.robovm.apple.foundation.NSArray;
import org.robovm.apple.foundation.NSAutoreleasePool;
import org.robovm.apple.foundation.NSError;
import org.robovm.apple.foundation.NSObject;
import org.robovm.apple.foundation.NSString;
import org.robovm.apple.foundation.NSURL;
import org.robovm.apple.uikit.UIActivityViewController;
import org.robovm.apple.uikit.UIApplication;
import org.robovm.apple.uikit.UIApplicationLaunchOptions;
import org.robovm.apple.uikit.UIViewController;
import org.robovm.objc.block.VoidBlock4;
import org.robovm.pods.google.games.GPGAchievement;
import org.robovm.pods.google.games.GPGAchievementUnlockCallback;
import org.robovm.pods.google.games.GPGLauncherController;
import org.robovm.pods.google.games.GPGLeaderboard;
import org.robovm.pods.google.games.GPGLeaderboardLoadScoresCallback;
import org.robovm.pods.google.games.GPGLeaderboardTimeScope;
import org.robovm.pods.google.games.GPGManager;
import org.robovm.pods.google.games.GPGPlayer;
import org.robovm.pods.google.games.GPGPlayerGetCallback;
import org.robovm.pods.google.games.GPGScore;
import org.robovm.pods.google.games.GPGScoreReport;
import org.robovm.pods.google.games.GPGScoreReportCallback;
import org.robovm.pods.google.games.GPGStatusDelegate;
import org.robovm.pods.google.mobileads.GADInterstitial;
import org.robovm.pods.google.mobileads.GADInterstitialDelegateAdapter;
import org.robovm.pods.google.mobileads.GADMobileAds;
import org.robovm.pods.google.mobileads.GADRequest;
import org.robovm.pods.google.mobileads.GADRequestError;
import org.robovm.pods.google.signin.GIDSignIn;
import org.robovm.pods.google.signin.GIDSignInUIDelegateAdapter;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class IOSLauncher extends IOSApplication.Delegate implements ActionResolver,GPGStatusDelegate {
    private static NearbyGPGSPlayers nearbyGPGSPlayers;
    public static final String CLIENT_ID_FREE = "xxxx.yy.z1";
    public static final String CLIENT_ID_NOADS = "xxxx.yy.z2";
    public static String CLIENT_ID = "";
    private IOSApplication app;
    static public GADInterstitial interstitial;
    static private GPGPlayer gpgplayer;
    private Screen postAdScreen;
    GADRequest request;
    IOSApplication local_app;

    @Override
    protected IOSApplication createApplication() {
        System.out.println("IOSLauncher:createApplication:start");
        if(Global.FREE_EDITION){
            CLIENT_ID = CLIENT_ID_FREE;
        }
        else{
            CLIENT_ID = CLIENT_ID_NOADS;
        }
        System.out.println("IOSLauncher:createApplication:Step1");
        IOSApplicationConfiguration config = new IOSApplicationConfiguration();
        System.out.println("IOSLauncher:createApplication:Step2");
        app =  new IOSApplication(CrosswordParty.getInstance(this), config);
        local_app = app;
        System.out.println("IOSLauncher:createApplication:configuring ads");

        GADMobileAds.disableSDKCrashReporting();
        createRequest();
       interstitial = createAndLoadInterstitial();
        System.out.println("IOSLauncher:createApplication:end");


        GIDSignIn.getSharedInstance().setUiDelegate(new GIDSignInUIDelegateAdapter() {
            private UIViewController libgdxViewController;

            @Override
            public void willDispatch(GIDSignIn signIn, NSError error) {
                Foundation.log("willDispatch()");
            }

            @Override
            public void presentViewController(GIDSignIn signIn, UIViewController viewController) {
                Foundation.log("presentViewController()");
                libgdxViewController =  UIApplication.getSharedApplication().getKeyWindow().getRootViewController();
                 //       .presentViewController(viewController, true, null);

                UIApplication.getSharedApplication().getKeyWindow().setRootViewController(viewController);

            }

            @Override
            public void dismissViewController(GIDSignIn signIn, UIViewController viewController) {
                Foundation.log("dismissViewController()");
                //viewController.dismissViewController(true, null);
                UIApplication.getSharedApplication().getKeyWindow().setRootViewController(libgdxViewController);

            }
        });

        return app;


    }

    public static void main(String[] argv) {
       System.out.println("IOSLauncher:main:start");
        NSAutoreleasePool pool = new NSAutoreleasePool();
        UIApplication.main(argv, null, IOSLauncher.class);
        pool.close();
        System.out.println("IOSLauncher:main:end");
    }

    @Override
    public boolean didFinishLaunching(UIApplication application, UIApplicationLaunchOptions launchOptions) {
        super.didFinishLaunching(application, launchOptions);
        Foundation.log("IOSLauncher didFinishLaunching()");

          //  GIDSignIn.getSharedInstance().setAllowsSignInWithWebView(true);

            GPGManager.getSharedInstance().signIn(CLIENT_ID, true);

        return true;
    }

    private GADInterstitial createAndLoadInterstitial() {
        System.out.println("IOSLauncher:createAndLoadInterstitial:here");

        if(Global.DEV_MODE){
            //interstitial = new GADInterstitial(GGLContextMobileAds.getSharedInstance().getAdUnitIDForInterstitialTest());
             interstitial = new GADInterstitial("xxxxx");
        }
        else{
            //interstitial = new GADInterstitial(GGLContextMobileAds.getSharedInstance().getConfiguration().getInterstitialAdUnitID());
             interstitial = new GADInterstitial("yyyyy");
        }


        interstitial.setDelegate(new GADInterstitialDelegateAdapter() {
            @Override
            public void didReceiveAd(GADInterstitial ad) {
                System.out.println("IOSLauncher:createAndLoadInterstitial:received ad.");

            }

            @Override
            public void didDismissScreen(GADInterstitial ad) {
                System.out.println("IOSLauncher:createAndLoadInterstitial:closed ad");
                CrosswordParty.getInstance().setScreen(postAdScreen);
            }

            @Override
            public void didFailToReceiveAd(GADInterstitial ad, GADRequestError error) {
                System.out.println("IOSLauncher:createAndLoadInterstitial:error" + error.description());
                System.out.println("IOSLauncher:createAndLoadInterstitial:error" + error.getErrorCode());

            }
        });
        interstitial.loadRequest(request);

        return interstitial;
    }

    private GADRequest createRequest() {
        System.out.println("IOSLauncher:createRequest:here");

        request = new GADRequest();

        // To test on your devices, add their UDIDs here:
        request.setTestDevices(Arrays.asList(GADRequest.getSimulatorID()));

        return request;
    }


    @Override
    public void showOrLoadInterstital(Screen aScreen) {
        System.out.println("IOSLauncher:showOrLoadInterstital:here");
        if(postAdScreen == null){
            postAdScreen = CrosswordParty.crosswordScreen;
        }
        if (postAdScreen.getClass() == CrosswordParty.crosswordScreen.getClass()) {
            postAdScreen = CrosswordParty.scrableScreen;
        } else {
            postAdScreen = CrosswordParty.crosswordScreen;

        }
        if (interstitial.isReady()) {
            System.out.println("IOSLauncher:showOrLoadInterstital:showing add!");
            UIViewController viewController = UIApplication.getSharedApplication().getKeyWindow().getRootViewController();
            interstitial.present(viewController);
            //interstitial.present(app.getUIViewController());

        } else {
            System.out.println("IOSLauncher:showOrLoadInterstital:Interstitial not ready!");
            CrosswordParty.getInstance().setScreen(postAdScreen);
        }
        createAndLoadInterstitial();
    }


    @Override
    public boolean getSignedInGPGS() {
        System.out.println("IOSLauncher:getSignedInGPGS:is Signed in? " + GPGManager.getSharedInstance().isSignedIn());
        return GPGManager.getSharedInstance().isSignedIn();
    }

    @Override
    public void loginGPGSSilently() {
        System.out.println("IOSLauncher:loginGPGSSilently:Start");
        if(!getSignedInGPGS()){
            try {
                GPGManager.getSharedInstance().signIn(CLIENT_ID, true);
                GPGManager.getSharedInstance().setStatusDelegate(this);

            } catch (final Exception ex) {
            }
        };
    }

    @Override
    public void loginGPGS() {
        System.out.println("IOSLauncher:loginGPGS:Start");
        if(!getSignedInGPGS()){
            try {
                GPGManager.getSharedInstance().signIn(CLIENT_ID, false);
                GPGManager.getSharedInstance().setStatusDelegate(this);

            } catch (final Exception ex) {
            }
        };
    }



    @Override
    public String getGPGSName() {
        if (GPGManager.getSharedInstance().isSignedIn()) {
            return gpgplayer.getDisplayName();
        } else{
            loginGPGS();
            return null;
        }
    }

    @Override
    public void submitScoreGPGS(int score) {
        System.out.println("IOSLauncher:submitScoreGPGS:here");
        GPGScore gpgScore = new GPGScore(Global.LEADERBOARD_SCORE);
        gpgScore.setValue(score);
        GPGScoreReportCallback gpgscoreReportCallback =  new GPGScoreReportCallback(){

            @Override
            public void done(GPGScoreReport report, NSError error) {
                if (error != null) {
                    System.out.println("IOSLauncher:submitScoreGPGS:Error");
                }
                else{
                    System.out.println("IOSLauncher:submitScoreGPGS:Done");
                }
            }
        };
        gpgScore.submitScore(gpgscoreReportCallback);
    }

    @Override
    public void submitStarChallengeScoreGPGS(int starChallenge) {
        System.out.println("IOSLauncher:submitStarChallengeScoreGPGS:here");
        GPGScore gpgScore = new GPGScore(Global.LEADERBOARD_STARSTREAK);
        gpgScore.setValue(starChallenge);
        GPGScoreReportCallback gpgscoreReportCallback =  new GPGScoreReportCallback(){
            @Override
            public void done(GPGScoreReport report, NSError error) {
                if (error != null) {
                    System.out.println("IOSLauncher:submitScoreGPGS:Error");
                }
                else{
                    System.out.println("IOSLauncher:submitScoreGPGS:Done");
                }
            }
        };
        gpgScore.submitScore(gpgscoreReportCallback);
    }

    @Override
    public void submitCrosswordChallengeScoreGPGS(int crosswordChallenge) {
        System.out.println("IOSLauncher:submitCrosswordChallengeScoreGPGS:here");
        GPGScore gpgScore = new GPGScore(Global.LEADERBOARD_COMBOS);
        gpgScore.setValue(crosswordChallenge);
        GPGScoreReportCallback gpgscoreReportCallback =  new GPGScoreReportCallback(){
            @Override
            public void done(GPGScoreReport report, NSError error) {
                if (error != null) {
                    System.out.println("IOSLauncher:submitScoreGPGS:Error");
                }
                else{
                    System.out.println("IOSLauncher:submitScoreGPGS:Done");
                }
            }
        };
        gpgScore.submitScore(gpgscoreReportCallback);
    }

    @Override
    public void unlockAchievementGPGS(String achievementId) {
        System.out.println("IOSLauncher:unlockAchievementGPGS:here");
        GPGAchievement gpgachievement = new GPGAchievement(achievementId);

        GPGAchievementUnlockCallback gpgachievementUnlockCallback = new GPGAchievementUnlockCallback() {
            @Override
            public void done(boolean newlyUnlocked, NSError error) {
                if (error != null) {
                    System.out.println("IOSLauncher:unlockAchievementGPGS:Error while unlocking!");
                } else {
                    System.out.println("IOSLauncher:unlockAchievementGPGS:unlock succeeded. newlyUnlocked: " + newlyUnlocked);
                }
            }
        };
        gpgachievement.unlock(gpgachievementUnlockCallback);
    }

    @Override
    public void getAllLeaderboardsGPGS() {
        System.out.println("IOSLauncher:getAllLeaderboardsGPGS:here");
        boolean isSignedInFlag = GPGManager.getSharedInstance().isSignedIn();
        System.out.println("IOSLauncher:loginGPGS:is signed in?" + isSignedInFlag);
        if (GPGManager.getSharedInstance().isSignedIn()) {
            GPGLauncherController.getSharedInstance().presentLeaderboardList();
        } else {
            loginGPGS();
        }
    }

    @Override
    public void getLeaderboardScoreGPGS() {
        System.out.println("IOSLauncher:getLeaderboardScoreGPGS:here");
        if (GPGManager.getSharedInstance().isSignedIn()) {
            GPGLauncherController.getSharedInstance().presentLeaderboard(Global.LEADERBOARD_SCORE);
        } else{
            loginGPGS();
            //     loginGPGS();
        }
    }

    @Override
    public void getLeaderboardStarChallengeGPGS() {
        System.out.println("IOSLauncher:getLeaderboardStarChallengeGPGS:here");
        if (GPGManager.getSharedInstance().isSignedIn()) {
            GPGLauncherController.getSharedInstance().presentLeaderboard(Global.LEADERBOARD_STARSTREAK);
        } else{
            loginGPGS();
        }
    }

    @Override
    public void getLeaderboardCrosswordChallengeGPGS() {
        System.out.println("IOSLauncher:getLeaderboardCrosswordChallengeGPGS:here");
        if (GPGManager.getSharedInstance().isSignedIn()) {
            GPGLauncherController.getSharedInstance().presentLeaderboard(Global.LEADERBOARD_COMBOS);

        } else{
            loginGPGS();
        }
    }

    @Override
    public void getAchievementsGPGS() {
        System.out.println("IOSLauncher:getAchievementsGPGS:here");

        if (GPGManager.getSharedInstance().isSignedIn()) {
            GPGLauncherController.getSharedInstance().presentAchievementList();

        } else{
            loginGPGS();
        }
    }



    @Override
    public void getNearbyPlayers() {
        System.out.println("IOSLauncher:getNearbyPlayers:here");
        if (GPGManager.getSharedInstance().isSignedIn()) {
            GPGLeaderboard gpgleaderboard = GPGLeaderboard.getLeaderboard(Global.LEADERBOARD_SCORE);
            gpgleaderboard.setSocial(true);
            gpgleaderboard.setPersonalWindow(true);
            gpgleaderboard.setTimeScope(GPGLeaderboardTimeScope.AllTime);


            GPGLeaderboardLoadScoresCallback gpgleaderboardLoadScoresCallback = new GPGLeaderboardLoadScoresCallback() {
                @Override
                public void done(NSArray<GPGScore> scores, NSError error) {
                    nearbyGPGSPlayers = new NearbyGPGSPlayers(gpgplayer.getPlayerId());

                    for(int i = 0;i< scores.size();i++){
                        GPGScore aScore = scores.get(i);
                        GPGPlayer aScorePlayer = aScore.getPlayer();
                        System.out.println("IOSLauncher:getNearbyPlayers:Player:" + aScorePlayer.getDisplayName() + "Score:" + aScore.getValue());
                        nearbyGPGSPlayers.addPlayer(aScorePlayer.getPlayerId(), aScorePlayer.getDisplayName(),aScore.getValue(),aScore.getFormattedRank());
                    }
                    nearbyGPGSPlayers.notify_Player();
                }
            };

            gpgleaderboard.loadScores(gpgleaderboardLoadScoresCallback);

        }
        else{
            loginGPGS();
        }


    }

    @Override
    public void sendGiftGrid(String textToShare, String subject, String URL) {
        NSArray<NSObject> items = new NSArray<>(
                new NSString(textToShare),
                new NSURL(URL));

        UIViewController viewController = UIApplication.getSharedApplication().getKeyWindow().getRootViewController();


       UIActivityViewController uiActivityViewController = new UIActivityViewController(items, null);
        uiActivityViewController.setCompletionWithItemsHandler(new VoidBlock4<String, Boolean, NSArray<NSObject>, NSError>() {
            @Override
            public void invoke(String s, Boolean aBoolean, NSArray<NSObject> nsObjects, NSError nsError) {
                GiftGridCombinations.getInstance().getSelectedCombination().setShared(true);

            }
        });
     /*   ((IOSApplication) Gdx.app).getUIViewController().presentViewController(uiActivityViewController, true, null);
*/
        viewController.presentViewController(uiActivityViewController, true, null);
    }

    @Override
    public void didFinishGamesSignIn(NSError error) {
        System.out.println("IOSLauncher:didFinishGamesSignIn:here");
        GPGPlayerGetCallback gpgplayerGetCallback = new GPGPlayerGetCallback(){

            @Override
            public void done(GPGPlayer player, NSError error) {
                gpgplayer = player;
                System.out.println("IOSLauncher:didFinishGamesSignIn:name:"+gpgplayer.getDisplayName()+":id:"+gpgplayer.getPlayerId());
                getNearbyPlayers();
            }
        };
        GPGPlayer.getLocalPlayer(gpgplayerGetCallback);


    }

    @Override
    public void didFinishGamesSignOut(NSError error) {
        System.out.println("IOSLauncher:didFinishGamesSignOut:here");

    }

    @Override
    public void didFinishGoogleAuth(NSError error) {
        System.out.println("IOSLauncher:didFinishGoogleAuth:here");
    }

    @Override
    public boolean shouldReauthenticate(NSError error) {
        System.out.println("IOSLauncher:shouldReauthenticate:here");

        return false;
    }

    @Override
    public void willReauthenticate(NSError error) {
        System.out.println("IOSLauncher:willReauthenticate:here");

    }
/*
    @Override
    public void finished(GTMOAuth2Authentication auth, NSError error) {
        System.out.println("IOSLauncher:finished:here");

    }
*/
    @Override
    public void didDisconnect(NSError error) {
        System.out.println("IOSLauncher:didDisconnect:here");

    }


/*

    @Override
    public boolean openURL(UIApplication application, NSURL url, String sourceApplication, NSPropertyList annotation) {
        System.out.println("IOSLauncher:openURL:here");
        boolean canRespond = GIDSignIn.getSharedInstance().handleURL(url, sourceApplication, annotation);
        if (canRespond) {
            return true;
        } else {
            // There might be other things you'd want to do here
            return false;
        }
    }
*/
    @Override
    public String getDateAsString(Date aDate, String format) {
        SimpleDateFormat SimpleDateFormat = new SimpleDateFormat(format) ;
        //DateTimeFormat dateFormat = DateTimeFormat.getFormat("yyyyMMddHHmmssS");

        TimeZone timeZone = TimeZone.getTimeZone("UTC");
        SimpleDateFormat.setTimeZone(timeZone);
        Calendar cal = Calendar.getInstance(timeZone);
        cal.setTime(aDate);
        return SimpleDateFormat.format(cal.getTime()).trim();
    }

    @Override
    public Date getStringAsDate(String aDate, String format) {
        SimpleDateFormat SimpleDateFormat = new SimpleDateFormat(format) ;
        TimeZone timeZone = TimeZone.getTimeZone("UTC");
        SimpleDateFormat.setTimeZone(timeZone);
        try {
            Date date = SimpleDateFormat.parse(aDate);
            return date;
        }
        catch(Exception e){
            return null;
        }
    }

    @Override
    public void runInBackground(Runnable toBeRun) {
        new Thread(toBeRun).start();
    }


}
Julien
  • 1,028
  • 9
  • 18

1 Answers1

-1

This is a problem in XCode. It should only happen when you debug with XCode so if you disconnect the phone from XCode and start the app you should not get the error. Might be fixed by going to Target->Capabilities and enable keychain sharing.

The issue should be fixed in XCode 8.2.

Jim
  • 995
  • 2
  • 11
  • 28
  • I do not use XCode. This is a LibGDX game (Java) created with Android Studio. This issue is happening with the simulator so I cannot disconnect the phone. I suppose there could be a work around if there is a way to add Target Compatibilities directly in the configuration file? – Julien Dec 10 '16 at 13:52
  • There is a similar issue with users on Xamarin (http://stackoverflow.com/questions/39487368/xamarin-auth-store-keychain-not-working-after-ios10-upgrade/39576798#39576798). There must be be a solution other than to wait for a new release to enable keychain sharing with LibGDX. – Julien Dec 10 '16 at 17:24
  • XCode 8.2 came out. Problem persists. – Julien Dec 14 '16 at 08:17
  • problem does not occur when running on a real device – Julien Dec 17 '16 at 09:49