Android - User only update certain file, not the whole .apk

I’m doing a quiz game for android.

my problem is, first of all, I set 100 questions and answers and publish in to google store.

then, after user install my game, they answer all the questions.

Several days, I update my game and added more questions and answers.

How do I want to make users only update the questions and answers only without update the whole .apk file?

currently question/answer are in .txt file.

Should I put questions/answers in a different method?

Where do you have that txt file located? Is it just in your project as TextAsset? In that case you can’t just update it since all assets are packed into the apk itself as asset.

The Google play store doesn’t allow to update “parts” of an apk. It can only update the apk, that’s it. However you can, if you have a webservice of some sort, place your txt file on your server and have your app loading it manually over the internet with the WWW class.

You might want to use a simple encryption so it’s not too easy for a user to get the txt manually and read out all answers ^^ A simple xor with a magic number would do to make it “hard to read”.

You could use Dropbox or something similar to host your file. There you can update it whenever you want. If it’s quite a bit of data you might want to use a “two files” approach. One that just contains a version number (which you increase at each update) and a second file which contains the actual data.

The app just has to query the “version” file and see if the locally stored file is outdated in which case you will load the data file. Once you have to data file you can store it on the device itself. Keep in mind to store the version number as well so you can compare it with the one on the server.

edit

Here’s an example how that two-files thing could look like:

public string VersionFileURL = "https://dl.dropboxusercontent.com/u/7761356/UnityAnswers/Data/Version.txt";
public string DataFileURL = "https://dl.dropboxusercontent.com/u/7761356/UnityAnswers/Data/Data.txt";
public string LocalVersionFileName = "Version.txt";
public string LocalDataFileName = "Data.txt";

public TextAsset defaultText;

[HideInInspector]
public string data = ""; // will contain your data
[HideInInspector]
public bool dataIsLoaded = false; // will be true when "data" contains useable data.

IEnumerator GetCachedData()
{
	dataIsLoaded = false;
	string versionFileName = System.IO.Path.Combine(Application.persistentDataPath, LocalVersionFileName);
	int oldVersion = -1;
	if (System.IO.File.Exists(versionFileName))
	{
		string versionString = System.IO.File.ReadAllText(versionFileName);
		if (!int.TryParse(versionString, out oldVersion))
			Debug.LogError("local 'version' file contains wrong data");
	}
	WWW www = new WWW(VersionFileURL);
	yield return www;
	if (!string.IsNullOrEmpty(www.error))
	{
		Debug.LogError("Version file could not be loaded. Wrong URL? No internet connection? " + www.error);
	}
	else if (string.IsNullOrEmpty(www.text))
	{
		Debug.LogError("Version file could not be loaded. Empty response");
	}
	else
	{
		string dataFileName = System.IO.Path.Combine(Application.persistentDataPath, LocalDataFileName);
		string versionString = www.text;
		int version = int.MaxValue;
		if (!int.TryParse(versionString, out version))
			Debug.LogError("'version' file contains wrong data");
		if (version > oldVersion)
		{
			www = new WWW(DataFileURL);
			yield return www;
			if (!string.IsNullOrEmpty(www.error))
			{
				Debug.LogError("Data file could not be loaded. Wrong URL? No internet connection? " + www.error);
			}
			else if (string.IsNullOrEmpty(www.text))
			{
				Debug.LogError("Data file could not be loaded. Empty response");
			}
			else
			{
				data = www.text;
				System.IO.File.WriteAllText(dataFileName, data);
				System.IO.File.WriteAllText(versionFileName, version.ToString());
				dataIsLoaded = true;
				yield break;
			}
		}
		// This will be executed when we can't load the new file or when it's version is still up to date
		if (System.IO.File.Exists(dataFileName))
		{
			// load the data from the local stored file
			data = System.IO.File.ReadAllText(dataFileName);
		}
		else
		{
			// fallback if everything else failed use the text from the TextAsset.
			data = defaultText.text;
		}
		dataIsLoaded = true;
	}
}

You just need to run that coroutine at start and wait for it to complete, or check “dataIsLoaded”. The “data” variable will contain the data from your textfile.

IEnumerator Start()
{
    yield return StartCoroutine(GetCachedData());
    // use the "data" variable here.
}

Keep in mind that depending on your internet reachability and speed GetCachedData() might take a few seconds to complete. You can’t use “data” before GetCachedData finishes. Usually some kind of busy / loading animation should be displayed during that time.

Important: Everytime you update your data txt file you have to increase the version number in the version txt file. Make sure you first update the data and afterwards you increase the version number. You should never reset or decrease the version number or users which already have loaded a higher version won’t get any updates until you reach and pass that version again.

You could increment the version number by as much as you want each update, but keep in mind if you set it to 1000 after the first update you can’t go back. Usually you would simply increase it by 1 each time.