Game dev: How to manage app content updates?

I’m building a game using React Native (Expo) and I’m currently trying to figure out how to handle game assets. I have a CMS where all game content (JSON data + images) is managed, and I’m currently fetching all of this content via HTTP when the app starts.

However I know that I can’t really do that anymore once I’m going to release the app, because the content will need to be bundled with it, without requiring an internet connection to launch it.

The content is fairly big, and I don’t want to include it in the git repository, because it’s not really part of the game code/engine. I also want the game to be able to fetch new content when it starts (if there’s a connection available) in order to be able to publish hot fixes for bugs that are caused by errors in the game content.

How can I manage this? What are the different options for approaching this?

PS. I’ve never released an app before so I don’t know much about handling updates

Expo’s OTA updates are really great for this. Asset bundle patterns are used to add the image assets to your binary so they’re available offline on first load, and Asset.loadAsync() can be used to download any images that are part of a future OTA update but weren’t included with the binary.

The issue is that this means that a game content update is an app update- there’s no way to update the two separately using Expo’s built-in stuff. When you publish an Expo app update, you’re re-bundling all of the JavaScript (and JSON) and assets used by the app, whether its for content or code. In the managed workflow, this might be the only way to include your content in the app binary at all (I’m not sure how else you would refer to images and JSON available offline in an Expo app except by importing them into your code).

That said, just because this content would be part of the code bundle you’re publishing to Expo, that doesn’t mean you can’t keep it out of your repo and in your CMS. I think you could customize your build pipeline to download the latest files to your project folder just before you publish. Put them in a folder that is also in your .gitignore file. The actual code files would have import/ require() references to the content files that aren’t actually there until you perform this download step.

Thank you! This is exactly the kind of help I was looking for. After doing my forum post I read up on both Asset bundle patterns, Asset.loadAsync() and have had the exact same thoughts as you write about.

I’m not sure what you mean here:

The issue is that this means that a game content update is an app update- there’s no way to update the two separately using Expo’s built-in stuff. When you publish an Expo app update, you’re re-bundling all of the JavaScript (and JSON) and assets used by the app, whether its for content or code. In the managed workflow, this might be the only way to include your content in the app binary at all (I’m not sure how else you would refer to images and JSON available offline in an Expo app except by importing them into your code).

I was thinking I could perhaps do something like this (some parts are exactly like you suggest):

  • Keep the remote assets in a separate folder in the project (using gitignore)
  • A script that downloads the assets (can be used pre publish to get latest content)
  • The app that is submitted to app stores will include the assets (using Asset bundle pattern + Asset.loadAsync)
  • On app startup, if there’s an internet connection, I’ll check a remote location (CMS or whatever) for new changes, and download the latest assets if needed. Assets are saved using FileSystem and Asset.loadAsync() is run on them.

This way, the content in the game always stays fresh. Sure, eventually the “over the air” content updates might become a little big (for example if a lot of images are replaced or added), but then I can just publish a new version app store version with the latest content bundled.

The only question I’m still having in regards to this solution is whether I can use FileSystem to update the assets. I mean - am I able to write files to the “project” itself? Or can FileSystem only access some arbitrary isolated app storage folder?

I was thinking almost the same thing except for the last step (my changes in bold)…

  1. Keep the remote assets in a separate folder in the project (using gitignore)
  2. A script that downloads the assets (can be used pre publish to get latest content)
  3. The app that is submitted to app stores will include the assets (using Asset bundle pattern + Asset.loadAsync)
  4. Next time you need to update game content, do steps 1 and 2 again, then expo publish (no need to build the binary). This creates an OTA update containing the latest content, which is downloaded and cached for future offline use by Expo’s update system the next time the app starts.

I think you could do something with FileSystem, though what it can access is at least semi-isolated, and I’m not sure it can access the offline assets. Also, those assets have funny internal names and I think it’d be a lot to manage. If you were able to do anything with FileSystem, I think it’d be something like use the Expo offline asset or your offline asset (with your code manually choosing between them). That’s complicated, though, which is why I suggest using Expo’s OTA update system for the initial offline bundling and OTA updates.

Right… I think that’s probably the smartest solution. Sure, I won’t be able to edit stuff on the fly in the CMS and have the app updated, but on the other side - I wouldn’t want that risk anyway. Using the built in OTA updates that Expo has is actually a big win in this case.

Thanks for the help!

1 Like