Android: Overwrite plugin cache when APK is updated
To allow updating APKs with new versions of Qt, we need to delete the old cache when the APK is updated. This patch does two things: 1. Move the plugins (and imports/qml) into a directory called qt-reserved-files/ to better separate the cache from the rest of the application. The first time the files are put here, we will delete the old cache in <datadir>/plugins, <datadir>/imports and <datadir>/qml if they exist to avoid leaving old files around forever. 2. Add versioning to the cache and flush it every time the APK is reinstalled. Potentially, the libraries in the APK can change for every reinstall, so this is the safest approach. Task-number: QTBUG-35129 [ChangeLog][Android][QTBUG-35129] Update deployed plugins and imports when APK is updated on the device. Change-Id: Ie38b639db2cfba8a521acc875c4afd5e07df3efd Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>bb10
parent
f9a47a6aa5
commit
58326e8585
|
|
@ -32,6 +32,8 @@ import java.io.OutputStream;
|
|||
import java.io.InputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -50,6 +52,7 @@ import android.content.ServiceConnection;
|
|||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.content.res.AssetManager;
|
||||
|
|
@ -382,6 +385,9 @@ public class QtActivity extends Activity
|
|||
InputStream inputStream = assetsManager.open(source);
|
||||
OutputStream outputStream = new FileOutputStream(destinationFile);
|
||||
copyFile(inputStream, outputStream);
|
||||
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
private static void createBundledBinary(String source, String destination)
|
||||
|
|
@ -401,13 +407,66 @@ public class QtActivity extends Activity
|
|||
InputStream inputStream = new FileInputStream(source);
|
||||
OutputStream outputStream = new FileOutputStream(destinationFile);
|
||||
copyFile(inputStream, outputStream);
|
||||
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
private void extractBundledPluginsAndImports(String localPrefix)
|
||||
private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion)
|
||||
{
|
||||
File versionFile = new File(pluginsPrefix + "cache.version");
|
||||
|
||||
long cacheVersion = 0;
|
||||
if (versionFile.exists() && versionFile.canRead()) {
|
||||
try {
|
||||
DataInputStream inputStream = new DataInputStream(new FileInputStream(versionFile));
|
||||
cacheVersion = inputStream.readLong();
|
||||
inputStream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheVersion != packageVersion) {
|
||||
deleteRecursively(new File(pluginsPrefix));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void extractBundledPluginsAndImports(String pluginsPrefix)
|
||||
throws IOException
|
||||
{
|
||||
ArrayList<String> libs = new ArrayList<String>();
|
||||
|
||||
String dataDir = getApplicationInfo().dataDir + "/";
|
||||
|
||||
long packageVersion = -1;
|
||||
try {
|
||||
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
|
||||
packageVersion = packageInfo.lastUpdateTime;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion))
|
||||
return;
|
||||
|
||||
{
|
||||
File versionFile = new File(pluginsPrefix + "cache.version");
|
||||
|
||||
File parentDirectory = versionFile.getParentFile();
|
||||
if (!parentDirectory.exists())
|
||||
parentDirectory.mkdirs();
|
||||
|
||||
versionFile.createNewFile();
|
||||
|
||||
DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(versionFile));
|
||||
outputStream.writeLong(packageVersion);
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
{
|
||||
String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY;
|
||||
java.util.Set<String> keys = m_activityInfo.metaData.keySet();
|
||||
|
|
@ -416,8 +475,8 @@ public class QtActivity extends Activity
|
|||
|
||||
for (String bundledImportBinary : list) {
|
||||
String[] split = bundledImportBinary.split(":");
|
||||
String sourceFileName = localPrefix + "lib/" + split[0];
|
||||
String destinationFileName = localPrefix + split[1];
|
||||
String sourceFileName = dataDir + "lib/" + split[0];
|
||||
String destinationFileName = pluginsPrefix + split[1];
|
||||
createBundledBinary(sourceFileName, destinationFileName);
|
||||
}
|
||||
}
|
||||
|
|
@ -431,7 +490,7 @@ public class QtActivity extends Activity
|
|||
for (String fileName : list) {
|
||||
String[] split = fileName.split(":");
|
||||
String sourceFileName = split[0];
|
||||
String destinationFileName = localPrefix + split[1];
|
||||
String destinationFileName = pluginsPrefix + split[1];
|
||||
copyAsset(sourceFileName, destinationFileName);
|
||||
}
|
||||
}
|
||||
|
|
@ -439,6 +498,45 @@ public class QtActivity extends Activity
|
|||
}
|
||||
}
|
||||
|
||||
private void deleteRecursively(File directory)
|
||||
{
|
||||
File[] files = directory.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory())
|
||||
deleteRecursively(file);
|
||||
else
|
||||
file.delete();
|
||||
}
|
||||
|
||||
directory.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix)
|
||||
{
|
||||
File newCache = new File(localPrefix);
|
||||
if (!newCache.exists()) {
|
||||
{
|
||||
File oldPluginsCache = new File(oldLocalPrefix + "plugins/");
|
||||
if (oldPluginsCache.exists() && oldPluginsCache.isDirectory())
|
||||
deleteRecursively(oldPluginsCache);
|
||||
}
|
||||
|
||||
{
|
||||
File oldImportsCache = new File(oldLocalPrefix + "imports/");
|
||||
if (oldImportsCache.exists() && oldImportsCache.isDirectory())
|
||||
deleteRecursively(oldImportsCache);
|
||||
}
|
||||
|
||||
{
|
||||
File oldQmlCache = new File(oldLocalPrefix + "qml/");
|
||||
if (oldQmlCache.exists() && oldQmlCache.isDirectory())
|
||||
deleteRecursively(oldQmlCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startApp(final boolean firstStart)
|
||||
{
|
||||
try {
|
||||
|
|
@ -464,11 +562,15 @@ public class QtActivity extends Activity
|
|||
if (m_activityInfo.metaData.containsKey("android.app.libs_prefix"))
|
||||
localPrefix = m_activityInfo.metaData.getString("android.app.libs_prefix");
|
||||
|
||||
String pluginsPrefix = localPrefix;
|
||||
|
||||
boolean bundlingQtLibs = false;
|
||||
if (m_activityInfo.metaData.containsKey("android.app.bundle_local_qt_libs")
|
||||
&& m_activityInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) {
|
||||
localPrefix = getApplicationInfo().dataDir + "/";
|
||||
extractBundledPluginsAndImports(localPrefix);
|
||||
pluginsPrefix = localPrefix + "qt-reserved-files/";
|
||||
cleanOldCacheIfNecessary(localPrefix, pluginsPrefix);
|
||||
extractBundledPluginsAndImports(pluginsPrefix);
|
||||
bundlingQtLibs = true;
|
||||
}
|
||||
|
||||
|
|
@ -484,8 +586,12 @@ public class QtActivity extends Activity
|
|||
if (m_activityInfo.metaData.containsKey("android.app.load_local_libs")) {
|
||||
String[] extraLibs = m_activityInfo.metaData.getString("android.app.load_local_libs").split(":");
|
||||
for (String lib : extraLibs) {
|
||||
if (lib.length() > 0)
|
||||
libraryList.add(localPrefix + lib);
|
||||
if (lib.length() > 0) {
|
||||
if (lib.startsWith("lib/"))
|
||||
libraryList.add(localPrefix + lib);
|
||||
else
|
||||
libraryList.add(pluginsPrefix + lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -513,9 +619,9 @@ public class QtActivity extends Activity
|
|||
}
|
||||
loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
|
||||
loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES
|
||||
+ "\tQML2_IMPORT_PATH=" + localPrefix + "/qml"
|
||||
+ "\tQML_IMPORT_PATH=" + localPrefix + "/imports"
|
||||
+ "\tQT_PLUGIN_PATH=" + localPrefix + "/plugins");
|
||||
+ "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml"
|
||||
+ "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports"
|
||||
+ "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins");
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (intent != null) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue