fix[MinecraftDownloader]: Implement caching SHA1 hashes for offline use

This commit is contained in:
alexytomi 2025-05-31 17:17:21 +08:00
parent 88a6bcb6a5
commit 4170e090f7
2 changed files with 59 additions and 8 deletions

View File

@ -21,6 +21,8 @@ import android.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.hardware.Sensor; import android.hardware.Sensor;
import android.hardware.SensorManager; import android.hardware.SensorManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
@ -1429,6 +1431,18 @@ public final class Tools {
OBSOLETE_RESOURCES_PATH = DIR_GAME_NEW + "/resources"; OBSOLETE_RESOURCES_PATH = DIR_GAME_NEW + "/resources";
} }
private static NetworkInfo getActiveNetworkInfo(Context ctx) {
ConnectivityManager connMgr = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return networkInfo; // This can return null when there is no wifi or data connected
}
public static boolean isOnline(Context ctx) {
NetworkInfo info = getActiveNetworkInfo(ctx);
if(info == null) return false;
return (info.isConnected());
}
public static boolean isDemoProfile(Context ctx){ public static boolean isDemoProfile(Context ctx){
MinecraftAccount currentProfile = PojavProfile.getCurrentProfileContent(ctx, null); MinecraftAccount currentProfile = PojavProfile.getCurrentProfileContent(ctx, null);
return currentProfile != null && currentProfile.isDemo(); return currentProfile != null && currentProfile.isDemo();

View File

@ -3,6 +3,9 @@ package net.kdt.pojavlaunch.tasks;
import static net.kdt.pojavlaunch.PojavApplication.sExecutorService; import static net.kdt.pojavlaunch.PojavApplication.sExecutorService;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -25,9 +28,12 @@ import net.kdt.pojavlaunch.value.DependentLibrary;
import net.kdt.pojavlaunch.value.MinecraftClientInfo; import net.kdt.pojavlaunch.value.MinecraftClientInfo;
import net.kdt.pojavlaunch.value.MinecraftLibraryArtifact; import net.kdt.pojavlaunch.value.MinecraftLibraryArtifact;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -56,6 +62,7 @@ public class MinecraftDownloader {
private static final ThreadLocal<byte[]> sThreadLocalDownloadBuffer = new ThreadLocal<>(); private static final ThreadLocal<byte[]> sThreadLocalDownloadBuffer = new ThreadLocal<>();
private boolean isLocalProfile = false; private boolean isLocalProfile = false;
private boolean isOnline;
/** /**
* Start the game version download process on the global executor service. * Start the game version download process on the global executor service.
@ -69,7 +76,9 @@ public class MinecraftDownloader {
@NonNull AsyncMinecraftDownloader.DoneListener listener) { @NonNull AsyncMinecraftDownloader.DoneListener listener) {
if(activity != null){ if(activity != null){
isLocalProfile = Tools.isLocalProfile(activity); isLocalProfile = Tools.isLocalProfile(activity);
isOnline = Tools.isOnline(activity);
Tools.switchDemo(Tools.isDemoProfile(activity)); Tools.switchDemo(Tools.isDemoProfile(activity));
} else { } else {
isLocalProfile = true; isLocalProfile = true;
Tools.switchDemo(true); Tools.switchDemo(true);
@ -82,9 +91,6 @@ public class MinecraftDownloader {
} }
downloadGame(activity, version, realVersion); downloadGame(activity, version, realVersion);
listener.onDownloadDone(); listener.onDownloadDone();
}catch (UnknownHostException e){
Log.i("DownloadMirror", e.toString());
Tools.showErrorRemote("Can't download Minecraft, no internet connection found", e);
}catch (Exception e) { }catch (Exception e) {
listener.onDownloadFailed(e); listener.onDownloadFailed(e);
} }
@ -473,7 +479,27 @@ public class MinecraftDownloader {
* Since Minecraft libraries are stored in maven repositories, try to use * Since Minecraft libraries are stored in maven repositories, try to use
* this when downloading libraries without hashes in the json. * this when downloading libraries without hashes in the json.
*/ */
private void tryGetLibrarySha1() { private void tryGetLibrarySha1() throws IOException {
File sha1CacheDir = new File(Tools.DIR_CACHE + "/sha1hashes");
File cacheFile = new File(sha1CacheDir.getAbsolutePath() + FileUtils.getFileName(mTargetUrl) + ".sha");
// Only use cache when its offline. No point in having cache invalidation now!
if (!isOnline) {
try (BufferedReader cacheFileReader = new BufferedReader(new FileReader(cacheFile))) {
mTargetSha1 = cacheFileReader.readLine();
if (mTargetSha1 != null) {
Log.i("MinecraftDownloader", "(No internet found) Reading Hash: " + mTargetSha1 + " from " + cacheFile);
} else if (cacheFile.exists()) {
Log.i("MinecraftDownloader", "(No internet found) Deleting invalid hash from cache: " + cacheFile);
cacheFile.delete();
}
} catch (FileNotFoundException ignored) {
mTargetSha1 = null;
Log.w("MinecraftDownloader", "(No internet found) Failed to read hash for " + cacheFile);
}
return;
}
String resultHash = null; String resultHash = null;
try { try {
resultHash = downloadSha1(); resultHash = downloadSha1();
@ -481,10 +507,21 @@ public class MinecraftDownloader {
mInternetUsageCounter.getAndAdd(40); mInternetUsageCounter.getAndAdd(40);
} catch (IOException e) { } catch (IOException e) {
Log.i("MinecraftDownloader", "Failed to download hash", e); Log.i("MinecraftDownloader", "Failed to download hash", e);
if (cacheFile.exists() && new BufferedReader(new FileReader(cacheFile)).readLine() == null) {
Log.i("MinecraftDownloader", "Deleting failed hash download from cache: " + cacheFile);
cacheFile.delete();
}
} }
if (resultHash != null) { if (resultHash != null) {
Log.i("MinecraftDownloader", "Got hash: " + resultHash + " for " + FileUtils.getFileName(mTargetUrl)); Log.i("MinecraftDownloader", "Got hash: " + resultHash + " for " + FileUtils.getFileName(mTargetUrl));
mTargetSha1 = resultHash; mTargetSha1 = resultHash;
if (!sha1CacheDir.exists()) {
sha1CacheDir.mkdir(); // If mkdir() fails, something went wrong with initializing /data/data/. mkdirs() isn't used on purpose
}
try (FileWriter writeHash = new FileWriter(cacheFile)) {
Log.i("MinecraftDownloader", "Saving hash: " + resultHash + " for " + FileUtils.getFileName(mTargetUrl) + " to " + cacheFile);
writeHash.write(resultHash);
}
} }
} }