Search Unity

[Utility library - iOS] GKNativeExtensions - The missing iOS cloud save feature!

Discussion in 'Assets and Asset Store' started by Dark-1-Games, Mar 13, 2019.

  1. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    We are excited to announce the release of GKNativeExtensions, a small native utility library made to support iOS Cloud save by using the apple-recommended GKSavedGame API.

    The utility library currently supports the following operations:
    • Fetching existing save games
    • Saving a game by name
    • Loading a game by name
    • Deleting a game by name
    • Resolve multiple conflicting saves
    • Registering a callback to be called when a conflict is detected
    • Registering a callback to be called when a save occurs on a different device (not properly tested)
    The project can be found on Github:
    https://github.com/dark-1-games/GKNativeExtensions

    It is licensed under the Mozilla Public License 2.0.

    This should technically work on OSX, but our focus has been iOS. Please let us know if you get it working on OSX.

    The library was made to be integrated in our upcoming cross-platform integration system, DarkCPS, for which we're currently looking for testers
    https://forum.unity.com/threads/darkcps-game-services-simplified-looking-for-testers.697136/

    Comments and feedback are welcome!
     

    Attached Files:

    Last edited: Oct 17, 2019
  2. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Conflict resolution and native callbacks (conflicts and new save) have been added, and version 0.2 is now available for download on github.
    Do note that the conflicting save games callback is only called if two devices save with the same name while disconnected, and only after restarting the game.
    It is possible to manually fetch games and detect the conflict by looking for multiple games with the same name but different deviceName.
     
    OlivierEsolu likes this.
  3. CoCoNutti

    CoCoNutti

    Joined:
    Nov 30, 2009
    Posts:
    504
    Thank you will check this out
     
  4. Zimbres

    Zimbres

    Joined:
    Nov 17, 2014
    Posts:
    100
    Hi there!

    It's great to count with some help on handling data with iCloud. I... i'm not much into c coding or osx, and I'm not sure if I got the whole thing.
    For example, importing the v0.2 unity package gives some errors, like this one:
    Assets/GKNativeExtensions/GKNativeExtensions.cs(83,13): error CS0019: Operator `+=' cannot be applied to operands of type `System.IntPtr' and `int'

    I'm not exactly used to... never touched a IntPtr to be honest. Any clue on why I'm having this problem? Something with Unity3d version? I'm using 2018.2.21f1.
     
  5. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Hey!
    Could you try replacing the contents of GKNativeExtensions.cs with this?
    https://raw.githubusercontent.com/d...ns/master/UnityBindings/GKNativeExtensions.cs

    The release version worked on .NET 4.5+. Since then, a small change by JBurkeKF added support for older versions, but we didn't make a new release.
     
    Zimbres likes this.
  6. Zimbres

    Zimbres

    Joined:
    Nov 17, 2014
    Posts:
    100
    Wow, thanks for the quick reply! I've replaced the code, all fine now! Will be testing the solution on various situations.
     
  7. Headup_Dev

    Headup_Dev

    Joined:
    Sep 18, 2013
    Posts:
    16
    Hi Dark-1-Games,

    have you tried this on tvos too?

    thx for the puplic repo btw :)
     
  8. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Hey there,
    Tvos has never been tested, since we don't have a device to test on but i assume the iOS version would work either OOB or with a couple of small tweaks.
    Please let me know if you manage to get it working, PRs are welcome.
     
    Zimbres and Headup_Dev like this.
  9. Zimbres

    Zimbres

    Joined:
    Nov 17, 2014
    Posts:
    100
    Dark-1, maybe it's a little too much to ask but... would you have a snippet on how to implement your solution? It's not only lazyness of mine, but it would help a lot on the ios building/xcode/iDevice upload routine.
     
  10. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Sure, we really didn't do any documenting on it, so here goes:

    • GKInit(Action<SavedGameDataGameCenter[]> conflictCallback, Action<SavedGameDataGameCenter> modifiedCallback)
      This will initialize the library and give you conflicts, if any exist, and call back the modifiedCallback once a saved game has been modified remotely.

    • GKFetchSavedGames(Action<SavedGameDataGameCenter[]> callback)
      Gets the available save games

    • GKResolveConflicts(SavedGameDataGameCenter[] sgData, byte[] saveArray, Action<bool> callback)
      Resolves the conflicts with the given new data. sgData is a list of conflicted save games, saveArray is the new data to save in bytes, callback executes once the command is finished.

    • GKDeleteGame(string savedGame, Action<bool> callback)
      Deletes a saved game by it's name.

    • GKSaveGame(byte[] data, string savedGameName, Action<SavedGameDataGameCenter> callback)
      Saves given data with a saved game name. The callback gets executed once done, with the resulting game data, or null if failed.

    • GKLoadGame(SavedGameDataGameCenter savedGame, Action<byte[]> savedDataCallback)
      Loads a saved game, and gives you back the loaded data in bytes.

    Note: If conflicts occur, GameKit doesn't ALWAYS tell you through the GKInit. It is necessary to find conflicts yourself by comparing names of SavedGameDataGameCenter returned by GKFetchSavedGames.

    Hope you find this short doc useful, i'll try to add it somewhere in the repo.
     
    Last edited: Jul 4, 2019
    RaL, Headup_Dev and Zimbres like this.
  11. Zimbres

    Zimbres

    Joined:
    Nov 17, 2014
    Posts:
    100
    Absolutely! Hope to report something useful as the time goes.
     
  12. Zimbres

    Zimbres

    Joined:
    Nov 17, 2014
    Posts:
    100
    Nothing really useful... I feel like I should update myself more on the field of delegates. I'm trying to initialize the plugin, but I'm not getting a sign of life. Is the following code correct?

    Code (CSharp):
    1. private void InitializeGKNE() {
    2.         Debug.Log("testando as coisa,");
    3.         GKNativeExtensions.GKInit(ConflictHappened, InitSuccessfull);
    4.     }
    5.     void ConflictHappened(SavedGameDataGameCenter[] ps) {
    6.         Debug.Log("params" + ps);
    7.         base.Initialize();
    8.     }
    9.     void InitSuccessfull(SavedGameDataGameCenter savedGameMeta) {
    10.         Debug.Log("initSuccessfull" + savedGameMeta);
    11. GKNativeExtensions.GKFetchSavedGames(FetchSavedGames);
     
  13. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Hey, sorry, it seems i got something mixed up, you don't need to wait for GKInit callbacks to begin working with the library.

    Code (CSharp):
    1.  
    2. Social.localUser.Authenticate((bool success) =>
    3. {
    4.     GKNativeExtensions.GKInit((conflicts) =>
    5.     {
    6.         Debug.Log("Conflicts received by C#");
    7.  
    8.     }, (modified) =>
    9.     {
    10.         Debug.Log("Modified game received by C#");
    11.     });
    12.  
    13.     if (!success)
    14.     {
    15.         callback(null);
    16.         return;
    17.     }
    18. });
    19.  
    20. // ... After GKInit is called...
    21.  
    22. GKNativeExtensions.GKFetchSavedGames((savedGameData) =>
    23. {
    24.     Debug.Log("Got saved games!");
    25. });
    26.  
    Also, may i interest you in another higher-level library we're working on, essentially covering the same stuff?
    https://forum.unity.com/threads/darkcps-game-services-simplified-looking-for-testers.697136/
     
    Headup_Dev likes this.
  14. Headup_Dev

    Headup_Dev

    Joined:
    Sep 18, 2013
    Posts:
    16
    Hey there,

    it looks like the class GKSavedGame from GameKit does not support tvOS at all. Other classes from GameKit work but GKSavedGame is excluded. I tried to build the library from XCode but could not get past this error. I am not a pro though so let me know if you have an idea how to fix this.
     
  15. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    I guess you're right, i can't see tvos listed here:
    https://developer.apple.com/documentation/gamekit/gksavedgame
    But it's available in GKLocalPlayer:
    https://developer.apple.com/documentation/gamekit/gklocalplayer

    Guess no tvOS :(
     
    Headup_Dev likes this.
  16. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    146
    @Dark-1-Games, hi! Thanks for the library.
    Can you please explain the procedure of initialization and loading of games stored in the cloud?
    As far as I understand, I should call GKInit and then call GKFetchSavedGames to get all the saved games and use one of them in GKLoadGame. If there are any conflicts I should get an array of conflicting games through the callback passed to GKInit. However, if there are no conflicts the callback won't be invoked, right?
    So on which stage should I wait for any conflicts to resolve them before loading actual data and use them in the game? Or do I misunderstand the concept behind GKResolveConflicts?
     
  17. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Hi,
    It's not super clear from apple's documentation when the conflicts callback is called exactly, but from prior testing i believe it's called if the game is running on one device and then another device saves the data at the same time (with a delay of a minute or more). However, if you're just starting the app and there's already a conflict, the callback won't be called. You need to also manually check for conflicting save game names when you get the loaded games back and call GKResolveConflicts with the resolution.

    To save yourself the headache of managing most of cloud features on iOS, Android and Steam, i would like to invite you to try out our unity asset, DarkCPS
     
  18. dotsquid

    dotsquid

    Joined:
    Aug 11, 2016
    Posts:
    146
    Thank you for a quick reply.
    Now it's a little bit clearer for me =)
    Thanks for your invitation, but the problem is the we've already released on Steam and now we are in a process of porting to iOS. So we already have an integration with Steam and switching to a 3rd-party plugin would take unnecessary time.
    Good luck with DarkCPS!
     
  19. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Sure, good luck with the project!
     
  20. denkacn

    denkacn

    Joined:
    May 13, 2011
    Posts:
    9
    Hi @Dark-1-Games
    An error occurred while building in Xcode
    Bitcode bundle could not be generated because '/Libraries/GKNativeExtensions/Plugins/IOS/libGKNativeExtensions.a(GKNativeExtensions.o)' was built without full bitcode. All object files and libraries for bitcode must be generated from Xcode Archive or Install build for architecture armv7
     
  21. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Hi,

    You can build from source with whichever options you want, just open up the GKNativeExtensions Xcode project and you're good to build.
     
  22. denkacn

    denkacn

    Joined:
    May 13, 2011
    Posts:
    9
    Ok, I try it, Thanks))
     
  23. Jeeeenunity

    Jeeeenunity

    Joined:
    Sep 16, 2017
    Posts:
    2
    Hi, thanks for the good lib.

    Unfortunately I am faced with the problem that iCloud synchronization doesn’t work at the first launch after installing of the app. Although I see that there are some save files on iCloud, GKNativeExtensions tells me that there are 0 save games for me. And after the second launch of the app synchronization works as it should.

    The second problem is that from time to time I receive an error «You don’t have permission to save the file “com~apple~CloudDocs_0456C65C-D519-481E-AB31-C94777627A03_15up.bundle” in the folder “com.apple.ubiquity”. This error blocks me from saving games to iCloud. It worth to mention that I have iCloud capability enabled, correct entitlements, and iCloud container for the app.

    Please tell me if there are some ways to solve these issues.

    Thanks.
     
  24. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    The first one is a known issue that's been reported to apple, and it seems like it's fixed in the latest beta of iOS. Meanwhile, a workaround is to wait for some time (like 5-10s) and poll for changes, only on the first launch.

    I've never encountered the second issue, but i think the issue might be that user is not successfully authenticated on gamecenter before the games are loaded.
     
    dotsquid likes this.
  25. Jeeeenunity

    Jeeeenunity

    Joined:
    Sep 16, 2017
    Posts:
    2
    Thanks! I'll give your workaround a try.
     
  26. pistoleta

    pistoleta

    Joined:
    Sep 14, 2017
    Posts:
    97
    I'm still experiencing the first synchronization problem, and I'm using iOS 13.3.1.
    Did you find any solution for this ?
    Thanks,
    pistoleta
     
  27. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Unfortunately the only workaround we have is to wait a bit longer on the first launch of the game or solve it through UI (no save game found, try again?).

    The issue is known by apple, but we couldn't say when it's getting released.
     
  28. pistoleta

    pistoleta

    Joined:
    Sep 14, 2017
    Posts:
    97
    Yes, thats what I'm doing right now... where do you check if these kind of bugs are known or not by apple? is there some kind of issue tracker or GitHub Issue like page? because I struggle every time I have to find apple info stuff related... and their community forums are not very responsive generally, at least I haven't get any answer...
    Thanks a lot
     
  29. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    I submitted a report using feedback assistant a while ago, this is the status:
     
    Last edited: Mar 18, 2020
  30. pistoleta

    pistoleta

    Joined:
    Sep 14, 2017
    Posts:
    97
    About the workaround of waiting x seconds on first run, it's quite messy, I've been able to test on different devices and the seconds it needs its quite variable depending on the device and of course the internet connection.

    Knowing there is data on iCloud to sync:
    -iPhone XR with 4g : 4.5 sec
    -iPhone XR with 3g: 7.1 sec

    -iPhone 6 with 4g/wifi: >13 seconds

    Ill try to test with more devices.
     
  31. pistoleta

    pistoleta

    Joined:
    Sep 14, 2017
    Posts:
    97
    Thats from your apple developer account I guess ?
     
  32. SergioCanos

    SergioCanos

    Joined:
    Jul 4, 2018
    Posts:
    2
    Hi, is there any reason why calls to GKResolveConflicts can only be made one at a time? For what I understand from Apple documentation (here), multiple calls can be made at the same time and those are solved asynchronously.

    Great library, btw, it´s helping us a lot!
     
  33. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    Hey, glad you like the library.
    It's definitely possible to do multiple calls, but the main issue is the complexity that arises if there are multiple calls at the same time, and the C# code should figure out which callback function to call. We decided to play it simple and safe and allow just one call at a time.
    PR requests are welcome, so if you decide to change this, hopefully we can integrate it back to the library.

    Cheers
     
  34. pistoleta

    pistoleta

    Joined:
    Sep 14, 2017
    Posts:
    97
    We are using this GameKit API:
    https://unionassets.com/ios-native-pro/saving-a-game-662

    But we found an important problem, there is no way to know if a savedGame has been correctly syncronized on iCloud. Am I right? We are using this in order to save the state of a game, this game can be accessed from different devices if you login from the same account (we have time tokens so sessions dont overlap)

    This works nice on good network conditions.

    But the problem comes when a device A with a weak connection, saves game, this game gets locally saved somewhere in the phone ( I would like to know where) but it won't synchronize until gets good connection. So, in the meanwhile device B can enter the game and mess up with the progress of device A.

    Is there any way of knowing if the changes device A made have been synchronized? I know there was a token on KVS but I dont see anything similar for this.

    Do any of the assets you guys use have a solution for this scenario?

    Thanks a lot in advance.
     
  35. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    I'm not sure what GameKit does internally, but i assume it just writes to an internal icloud storage location and syncs the game when it gets the chance.
    Overlapping saves are possible, but i'd just let the conflict callback take care of it. The user will most likely notice the save is wrong, and should be presented with conflict resolution options, when the conflict is detected. There's not much else you can do anyways.
     
  36. pistoleta

    pistoleta

    Joined:
    Sep 14, 2017
    Posts:
    97
    No no, the problem is not the conflict, actually by not letting 2 devices run at the same time you are almost guaranteed to not have conflicts, anyway I have a conflict resolution system.

    The problem is, a device with poor connection not being able to synchronize the saved game... so device B when gets the chance to enter the game (5 mins later) does not have the last version of it.

    Thanks for your answer!
     
  37. Dark-1-Games

    Dark-1-Games

    Joined:
    Mar 26, 2014
    Posts:
    35
    I understood completely, but there's simply no way to guarantee that a save from device A is synchronized on device B. Perhaps the game is running on device A which is in airplane mode, has zero connection, and the player makes a lot of progress. The player, when playing on the device B (5 minutes later) will notice he's playing on a wrong save, and should get a prompt to resolve when device A is back online and the conflict can be detected. That's the only way to go about this in my opinion.

    Cheers
     
  38. pistoleta

    pistoleta

    Joined:
    Sep 14, 2017
    Posts:
    97
    Understood, I got it, thanks a lot!!:)
     
  39. SergioCanos

    SergioCanos

    Joined:
    Jul 4, 2018
    Posts:
    2
    Hi again, we are trying to make teh plugin work, but so far we are not getting any callback called from it. What settings should the library in Unity have? Should we configure something on xCode besides iCloud capabilities to make it function as expected?
     
unityunity