11package starray .android .modmanager ;
22
33import android .app .Activity ;
4- import android .app .AlarmManager ;
54import android .app .AlertDialog ;
6- import android .app .PendingIntent ;
7- import android .content .Context ;
5+ import android .content .Intent ;
86import android .os .Handler ;
97import android .os .Looper ;
108import android .os .Process ;
119import android .util .Log ;
1210
11+ import com .alibaba .fastjson2 .JSON ;
12+ import com .alibaba .fastjson2 .annotation .JSONField ;
13+
1314import java .io .BufferedInputStream ;
1415import java .io .File ;
1516import java .io .IOException ;
3940public class ModManagerUpdater {
4041
4142 private static final String TAG = "ModManagerUpdater" ;
43+ private static final String PROXY_URL = "https://gh-proxy.org/" ;
4244
4345 private final Activity activity ;
4446 private String versionJsonUrl ;
4547 private Path basePath ;
48+ private boolean useProxy = true ;
4649
4750 public static ModManagerUpdater create (Activity activity ) {
4851 return new ModManagerUpdater (activity );
@@ -67,6 +70,12 @@ public ModManagerUpdater basePath(Path path) {
6770 return this ;
6871 }
6972
73+ /** 是否在下载时使用 gh-proxy 代理(默认 true) */
74+ public ModManagerUpdater useProxy (boolean useProxy ) {
75+ this .useProxy = useProxy ;
76+ return this ;
77+ }
78+
7079 // ──── 入口 ────
7180
7281 public void start () {
@@ -92,7 +101,7 @@ public void start(boolean useNewThread) {
92101 VersionInfo localVersion = null ;
93102 try {
94103 if (Files .exists (localDll ) && Files .exists (localVerFile )) {
95- localVersion = parseVersionJson (new String (Files .readAllBytes (localVerFile )));
104+ localVersion = JSON . parseObject (new String (Files .readAllBytes (localVerFile )), VersionInfo . class );
96105 Log .i (TAG , "Local version: " + localVersion .version + " (code=" + localVersion .versionCode + ")" );
97106 } else {
98107 Log .i (TAG , "No local manager found" );
@@ -170,6 +179,15 @@ private void showUpdateDialog(VersionInfo remote, Path mgr, Path rt, Path mods,
170179 }
171180
172181 private void showDownloadDialog (VersionInfo remote , Path mgr , Path rt , Path mods , boolean hasLocal , boolean useNewThread ) {
182+ if (hasLocal ) {
183+ // 删除本地 version.json,确保更新失败时不会误认为已有可用版本
184+ try {
185+ Files .deleteIfExists (mgr .resolve ("version.json" ));
186+ Log .i (TAG , "Deleted local version.json before update" );
187+ } catch (IOException e ) {
188+ Log .w (TAG , "Failed to delete local version.json: " + e .getMessage ());
189+ }
190+ }
173191 Log .i (TAG , "Starting download: url=" + remote .managerUrl + " target=" + mgr );
174192 var dialog = new AlertDialog .Builder (activity )
175193 .setTitle (hasLocal ? "更新中" : "下载中" )
@@ -248,9 +266,8 @@ private Path downloadAndExtractSync(VersionInfo version, Path targetDir, AlertDi
248266 clearDirectory (targetDir .toFile ());
249267 unzip (zipFile , targetDir );
250268
251- var marker = "{\" version\" :\" " + version .version +
252- "\" ,\" versionCode\" :" + version .versionCode + "}" ;
253- Files .write (targetDir .resolve ("version.json" ), marker .getBytes ());
269+ Files .write (targetDir .resolve ("version.json" ),
270+ JSON .toJSONBytes (version ));
254271
255272 Files .delete (zipFile );
256273 Log .i (TAG , "Manager installed successfully" );
@@ -288,40 +305,35 @@ private void launch(Path mgr, Path rt, Path mods, boolean useNewThread) {
288305 }
289306 // ──── 远程版本 ────
290307
291- private VersionInfo fetchVersionJson () {
308+ private VersionInfo fetchVersionJson () {
292309 try {
293310 var json = httpGetString (versionJsonUrl );
294- return parseVersionJson (json );
311+ return JSON . parseObject (json , VersionInfo . class );
295312 } catch (IOException e ) {
296313 Log .e (TAG , "Failed to fetch version.json: " + e .getMessage (), e );
297314 throw new UncheckedIOException (e );
298315 }
299316 }
300317
301- private static class VersionInfo {
302- String version ;
303- int versionCode ;
304- String managerUrl ;
305- String sha256 ;
306- }
307-
308- private static VersionInfo parseVersionJson (String json ){
309- var v = new VersionInfo ();
310- v .version = extractJsonString (json , "version" );
311- try {
312- v .versionCode = Integer .parseInt (extractJsonString (json , "versionCode" , "0" ));
313- } catch (NumberFormatException e ) {
314- v .versionCode = 0 ;
315- }
316- v .managerUrl = extractJsonString (json , "manager" );
317- v .sha256 = extractJsonString (json , "sha256" , "" );
318- return v ;
318+ public static class VersionInfo {
319+ @ JSONField (name = "version" )
320+ public String version ;
321+ @ JSONField (name = "versionCode" )
322+ public int versionCode ;
323+ @ JSONField (name = "manager" )
324+ public String managerUrl ;
325+ @ JSONField (name = "sha256" )
326+ public String sha256 ;
319327 }
320328
321329 // ──── HTTP ────
322330
323- private static String httpGetString (String urlStr ) throws IOException {
324- var conn = openConnection (urlStr , 15_000 , 15_000 );
331+ private String proxyUrl (String url ) {
332+ return useProxy ? PROXY_URL + url : url ;
333+ }
334+
335+ private String httpGetString (String urlStr ) throws IOException {
336+ var conn = openConnection (proxyUrl (urlStr ), 15_000 , 15_000 );
325337 try (var in = conn .getInputStream ();
326338 var out = new java .io .ByteArrayOutputStream ()) {
327339 byte [] buf = new byte [4096 ];
@@ -338,10 +350,11 @@ private interface ProgressCallback {
338350 void onProgress (int percent );
339351 }
340352
341- private static void downloadFile (String urlStr , Path dest , ProgressCallback cb ) throws
353+ private void downloadFile (String urlStr , Path dest , ProgressCallback cb ) throws
342354 IOException {
343- Log .i (TAG , "Downloading " + urlStr );
344- var conn = openConnection (urlStr , 30_000 , 120_000 );
355+ var realUrl = proxyUrl (urlStr );
356+ Log .i (TAG , "Downloading " + realUrl );
357+ var conn = openConnection (realUrl , 30_000 , 120_000 );
345358 int cl = conn .getContentLength ();
346359 Log .i (TAG , "Content-Length: " + cl );
347360 try (var in = new BufferedInputStream (conn .getInputStream ());
@@ -415,7 +428,7 @@ private static void clearDirectory (File dir){
415428
416429 // ──── 重启 ────
417430
418- private void restartApp () {
431+ private void restartApp () {
419432 Log .i (TAG , "Restarting app..." );
420433 var intent = activity .getPackageManager ()
421434 .getLaunchIntentForPackage (activity .getPackageName ());
@@ -424,12 +437,10 @@ private void restartApp () {
424437 Process .killProcess (Process .myPid ());
425438 return ;
426439 }
427- int flags = PendingIntent .FLAG_ONE_SHOT | PendingIntent .FLAG_IMMUTABLE ;
428- var pending = PendingIntent .getActivity (activity , 0 , intent , flags );
429- var alarm = (AlarmManager ) activity .getSystemService (Context .ALARM_SERVICE );
430- alarm .set (AlarmManager .RTC , System .currentTimeMillis () + 200 , pending );
431- Log .i (TAG , "Alarm scheduled, killing process" );
432- Process .killProcess (Process .myPid ());
440+ intent .addFlags (Intent .FLAG_ACTIVITY_CLEAR_TOP | Intent .FLAG_ACTIVITY_NEW_TASK );
441+ activity .startActivity (intent );
442+ activity .finishAffinity ();
443+ Runtime .getRuntime ().exit (0 );
433444 }
434445
435446 private static void updateDialog (AlertDialog d , String msg ,int pct ){
@@ -439,21 +450,5 @@ private static void updateDialog (AlertDialog d, String msg,int pct){
439450 }
440451
441452 private static final Handler mainHandler = new Handler (Looper .getMainLooper ());
442-
443- // ──── JSON ────
444-
445- private static String extractJsonString (String json , String key ){
446- return extractJsonString (json , key , null );
447- }
448-
449- private static String extractJsonString (String json , String key , String def ){
450- var p = "\" " + key + "\" " ;
451- int s = json .indexOf (p );
452- if (s < 0 ) return def ;
453- s = json .indexOf ('"' , s + p .length ());
454- if (s < 0 ) return def ;
455- int e = json .indexOf ('"' , s + 1 );
456- return e < 0 ? def : json .substring (s + 1 , e );
457- }
458453}
459454
0 commit comments