修复点击效果和安装权限问题
- 修复Hook类中canRequestPackageInstalls()返回false导致的安装失败问题 - 优化点击效果颜色,从刺眼的亮黄色改为柔和的半透明白色 - 调整选中状态背景色,使用更柔和的半透明黄色 - 清理项目中的临时文件和重复文件 - 更新版本号到3.0.8
This commit is contained in:
@@ -32,7 +32,7 @@ public class Updater implements Download.Callback {
|
||||
private boolean forceCheck; // 是否为手动检查
|
||||
|
||||
private File getFile() {
|
||||
return Path.cache("update.apk");
|
||||
return Path.root("Download", "XMBOX-update.apk");
|
||||
}
|
||||
|
||||
private String getJson() {
|
||||
@@ -40,6 +40,26 @@ public class Updater implements Download.Callback {
|
||||
}
|
||||
|
||||
private String getApk() {
|
||||
// 使用JSON中指定的具体下载路径
|
||||
try {
|
||||
String response = OkHttp.string(getJson());
|
||||
JSONObject object = new JSONObject(response);
|
||||
JSONObject downloads = object.optJSONObject("downloads");
|
||||
if (downloads != null) {
|
||||
String abi = BuildConfig.FLAVOR_abi;
|
||||
String downloadPath = downloads.optString(abi);
|
||||
if (!downloadPath.isEmpty()) {
|
||||
// 直接构建完整URL,不通过Github.getApk()避免重复添加路径
|
||||
String baseUrl = Github.useCnMirror() ?
|
||||
"https://gitee.com/ochenoktochen/XMBOX-Release/raw/main" :
|
||||
"https://raw.githubusercontent.com/Tosencen/XMBOX-Release/main";
|
||||
return baseUrl + "/apk/" + (dev ? "dev" : "release") + "/" + downloadPath;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.e("Failed to get download path from JSON: " + e.getMessage());
|
||||
}
|
||||
// 回退到原来的方式
|
||||
return Github.getApk(dev, BuildConfig.FLAVOR_mode + "-" + BuildConfig.FLAVOR_abi);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,13 @@ package com.fongmi.android.tv.utils;
|
||||
|
||||
import com.fongmi.android.tv.App;
|
||||
import com.github.catvod.net.OkHttp;
|
||||
import com.github.catvod.utils.Logger;
|
||||
import com.github.catvod.utils.Path;
|
||||
import com.google.common.net.HttpHeaders;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -47,14 +49,22 @@ public class Download {
|
||||
private void doInBackground() {
|
||||
try (Response res = OkHttp.newCall(url, url).execute()) {
|
||||
Path.create(file);
|
||||
download(res.body().byteStream(), Double.parseDouble(res.header(HttpHeaders.CONTENT_LENGTH, "1")));
|
||||
long expectedLength = Long.parseLong(res.header(HttpHeaders.CONTENT_LENGTH, "0"));
|
||||
download(res.body().byteStream(), expectedLength);
|
||||
|
||||
// 验证下载的文件
|
||||
if (!verifyDownloadedFile(file, expectedLength)) {
|
||||
App.post(() -> {if (callback != null) callback.error("下载的文件可能已损坏,请重试");});
|
||||
return;
|
||||
}
|
||||
|
||||
App.post(() -> {if (callback != null) callback.success(file);});
|
||||
} catch (Exception e) {
|
||||
App.post(() -> {if (callback != null) callback.error(e.getMessage());});
|
||||
}
|
||||
}
|
||||
|
||||
private void download(InputStream is, double length) throws Exception {
|
||||
private void download(InputStream is, long length) throws Exception {
|
||||
try (BufferedInputStream input = new BufferedInputStream(is); FileOutputStream os = new FileOutputStream(file)) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int readBytes;
|
||||
@@ -68,6 +78,45 @@ public class Download {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean verifyDownloadedFile(File file, long expectedLength) {
|
||||
try {
|
||||
// 检查文件大小
|
||||
if (file.length() != expectedLength) {
|
||||
Logger.e("File size mismatch: expected " + expectedLength + ", actual " + file.length());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查APK文件头 (ZIP文件头)
|
||||
if (file.length() < 4) return false;
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
byte[] header = new byte[4];
|
||||
fis.read(header);
|
||||
// ZIP文件头应该是 0x504B0304 (PK..)
|
||||
if (header[0] != 0x50 || header[1] != 0x4B || header[2] != 0x03 || header[3] != 0x04) {
|
||||
Logger.e("Invalid APK file header");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 额外验证:检查APK文件是否完整
|
||||
// 尝试读取ZIP文件结构
|
||||
fis.getChannel().position(0);
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead = fis.read(buffer);
|
||||
if (bytesRead < 4) {
|
||||
Logger.e("APK file too small or corrupted");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.d("APK file verification passed: " + file.getName() + " (" + file.length() + " bytes)");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Logger.e("File verification failed: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
|
||||
void progress(int progress);
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.core.content.FileProvider;
|
||||
import com.fongmi.android.tv.App;
|
||||
import com.fongmi.android.tv.R;
|
||||
import com.fongmi.android.tv.impl.Callback;
|
||||
import com.github.catvod.utils.Logger;
|
||||
import com.github.catvod.utils.Path;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
@@ -34,11 +35,35 @@ public class FileUtil {
|
||||
}
|
||||
|
||||
public static void openFile(File file) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.setDataAndType(getShareUri(file), FileUtil.getMimeType(file.getName()));
|
||||
App.get().startActivity(intent);
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
||||
// 对于APK文件,使用特定的MIME类型
|
||||
String mimeType = file.getName().toLowerCase().endsWith(".apk") ?
|
||||
"application/vnd.android.package-archive" : getMimeType(file.getName());
|
||||
|
||||
intent.setDataAndType(getShareUri(file), mimeType);
|
||||
|
||||
// 添加额外的安装权限检查
|
||||
if (file.getName().toLowerCase().endsWith(".apk")) {
|
||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
}
|
||||
|
||||
App.get().startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
Logger.e("Failed to open file: " + e.getMessage());
|
||||
// 如果失败,尝试使用通用方式
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setDataAndType(getShareUri(file), "*/*");
|
||||
App.get().startActivity(intent);
|
||||
} catch (Exception ex) {
|
||||
Logger.e("Fallback open file also failed: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void gzipCompress(File target) {
|
||||
|
||||
@@ -32,7 +32,7 @@ public class Updater implements Download.Callback {
|
||||
private boolean forceCheck; // 是否为手动检查
|
||||
|
||||
private File getFile() {
|
||||
return Path.cache("update.apk");
|
||||
return Path.root("Download", "XMBOX-update.apk");
|
||||
}
|
||||
|
||||
private String getJson() {
|
||||
@@ -40,7 +40,31 @@ public class Updater implements Download.Callback {
|
||||
}
|
||||
|
||||
private String getApk() {
|
||||
return Github.getApk(dev, BuildConfig.FLAVOR_mode + "-" + BuildConfig.FLAVOR_abi);
|
||||
// 使用JSON中指定的具体下载路径
|
||||
try {
|
||||
String response = OkHttp.string(getJson());
|
||||
JSONObject object = new JSONObject(response);
|
||||
JSONObject downloads = object.optJSONObject("downloads");
|
||||
if (downloads != null) {
|
||||
String abi = BuildConfig.FLAVOR_abi;
|
||||
String downloadPath = downloads.optString(abi);
|
||||
if (!downloadPath.isEmpty()) {
|
||||
// 直接构建完整URL,不通过Github.getApk()避免重复添加路径
|
||||
String baseUrl = Github.useCnMirror() ?
|
||||
"https://gitee.com/ochenoktochen/XMBOX-Release/raw/main" :
|
||||
"https://raw.githubusercontent.com/Tosencen/XMBOX-Release/main";
|
||||
String fullUrl = baseUrl + "/apk/" + (dev ? "dev" : "release") + "/" + downloadPath;
|
||||
Logger.d("APK download URL: " + fullUrl);
|
||||
return fullUrl;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.e("Failed to get download path from JSON: " + e.getMessage());
|
||||
}
|
||||
// 回退到原来的方式
|
||||
String fallbackUrl = Github.getApk(dev, BuildConfig.FLAVOR_mode + "-" + BuildConfig.FLAVOR_abi);
|
||||
Logger.d("APK fallback URL: " + fallbackUrl);
|
||||
return fallbackUrl;
|
||||
}
|
||||
|
||||
public static Updater create() {
|
||||
@@ -83,11 +107,17 @@ public class Updater implements Download.Callback {
|
||||
}
|
||||
|
||||
private void doInBackground(Activity activity) {
|
||||
Logger.d("Updater: Starting update check...");
|
||||
try {
|
||||
String response = OkHttp.string(getJson());
|
||||
String jsonUrl = getJson();
|
||||
Logger.d("Updater: JSON URL: " + jsonUrl);
|
||||
|
||||
String response = OkHttp.string(jsonUrl);
|
||||
Logger.d("Updater: JSON response length: " + response.length());
|
||||
|
||||
// 检查响应是否包含错误信息,只在手动检查时提示
|
||||
if (response.contains("rate limit exceeded")) {
|
||||
Logger.e("Updater: Rate limit exceeded");
|
||||
if (forceCheck) {
|
||||
App.post(() -> Notify.show("检查更新失败:API请求过于频繁,请稍后重试"));
|
||||
}
|
||||
@@ -95,6 +125,7 @@ public class Updater implements Download.Callback {
|
||||
}
|
||||
|
||||
if (response.contains("Not Found Project") || response.contains("Not Found")) {
|
||||
Logger.e("Updater: Project not found");
|
||||
if (forceCheck) {
|
||||
App.post(() -> Notify.show("检查更新失败:更新服务暂时不可用"));
|
||||
}
|
||||
@@ -105,9 +136,15 @@ public class Updater implements Download.Callback {
|
||||
String name = object.optString("name");
|
||||
String desc = object.optString("desc");
|
||||
int code = object.optInt("code");
|
||||
|
||||
Logger.d("Updater: Remote version: " + name + " (code: " + code + ")");
|
||||
Logger.d("Updater: Local version: " + BuildConfig.VERSION_NAME + " (code: " + BuildConfig.VERSION_CODE + ")");
|
||||
|
||||
if (need(code, name)) {
|
||||
Logger.d("Updater: Update needed, showing dialog");
|
||||
App.post(() -> show(activity, name, desc));
|
||||
} else {
|
||||
Logger.d("Updater: No update needed");
|
||||
// 只在手动检查时提示已是最新版
|
||||
if (forceCheck) {
|
||||
App.post(() -> Notify.show("已是最新版本 " + name));
|
||||
@@ -115,6 +152,7 @@ public class Updater implements Download.Callback {
|
||||
Logger.d("Already latest version: " + name);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.e("Updater: Exception during update check: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
// 只在手动检查时提示网络错误
|
||||
if (forceCheck) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
android:color="?attr/colorControlHighlight">
|
||||
<item android:id="@android:id/background">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/yellow_500" />
|
||||
<solid android:color="@color/yellow_50" />
|
||||
<corners android:radius="8dp" />
|
||||
<padding
|
||||
android:bottom="14dp"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
android:color="?attr/colorControlHighlight">
|
||||
<item android:id="@android:id/background">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/yellow_500" />
|
||||
<solid android:color="@color/yellow_50" />
|
||||
<corners android:radius="8dp" />
|
||||
<padding
|
||||
android:bottom="10dp"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
android:color="?attr/colorControlHighlight">
|
||||
<item android:id="@android:id/background">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/yellow_500" />
|
||||
<solid android:color="@color/yellow_50" />
|
||||
<corners android:radius="8dp" />
|
||||
<padding
|
||||
android:bottom="18dp"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
android:color="?attr/colorControlHighlight">
|
||||
<item android:id="@android:id/background">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/yellow_500" />
|
||||
<solid android:color="@color/yellow_50" />
|
||||
<corners android:radius="8dp" />
|
||||
<padding
|
||||
android:bottom="18dp"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primaryDark</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
<item name="colorControlHighlight">@color/primary</item>
|
||||
<item name="colorControlHighlight">@color/white_20</item>
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="android:windowDisablePreview">true</item>
|
||||
<item name="android:navigationBarColor">@color/transparent</item>
|
||||
|
||||
Reference in New Issue
Block a user