mirror of
https://github.com/zimplexing/OrionTV.git
synced 2026-02-15 04:14:42 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
619901ef69 | ||
|
|
8523e5f157 | ||
|
|
29ad5a5e75 | ||
|
|
cf854c3c9f | ||
|
|
a86eb8ca5c | ||
|
|
487c15d8b6 | ||
|
|
3526189e32 | ||
|
|
c473581c26 |
@@ -2,7 +2,7 @@
|
|||||||
"name": "OrionTV",
|
"name": "OrionTV",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "expo-router/entry",
|
"main": "expo-router/entry",
|
||||||
"version": "1.3.11",
|
"version": "1.3.13",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "EXPO_TV=1 EXPO_USE_METRO_WORKSPACE_ROOT=1 expo start",
|
"start": "EXPO_TV=1 EXPO_USE_METRO_WORKSPACE_ROOT=1 expo start",
|
||||||
"android": "EXPO_TV=1 EXPO_USE_METRO_WORKSPACE_ROOT=1 expo run:android",
|
"android": "EXPO_TV=1 EXPO_USE_METRO_WORKSPACE_ROOT=1 expo run:android",
|
||||||
|
|||||||
@@ -167,32 +167,29 @@ class UpdateService {
|
|||||||
* 4️⃣ 安装 APK(只在 Android 可用,使用 expo-intent-launcher)
|
* 4️⃣ 安装 APK(只在 Android 可用,使用 expo-intent-launcher)
|
||||||
* --------------------------------------------------------------- */
|
* --------------------------------------------------------------- */
|
||||||
async installApk(fileUri: string): Promise<void> {
|
async installApk(fileUri: string): Promise<void> {
|
||||||
// if (!Device.isDevice) {
|
// ① 先确认文件存在
|
||||||
// // 在模拟器里打开文件会报错,直接给用户提示
|
|
||||||
// Toast.show({
|
|
||||||
// type: 'error',
|
|
||||||
// text1: '安装失败',
|
|
||||||
// text2: '模拟器不支持直接安装 APK,请在真机上操作',
|
|
||||||
// });
|
|
||||||
// throw new Error('Cannot install on simulator');
|
|
||||||
// }
|
|
||||||
|
|
||||||
const exists = await FileSystem.getInfoAsync(fileUri);
|
const exists = await FileSystem.getInfoAsync(fileUri);
|
||||||
if (!exists.exists) {
|
if (!exists.exists) {
|
||||||
throw new Error(`APK not found at ${fileUri}`);
|
throw new Error(`APK not found at ${fileUri}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Android 需要给 Intent 设置 mime 类型,并且使用 ACTION_VIEW
|
// ② 把 file:// 转成 content://,Expo‑FileSystem 已经实现了 FileProvider
|
||||||
|
const contentUri = await FileSystem.getContentUriAsync(fileUri);
|
||||||
|
|
||||||
|
// ③ 只在 Android 里执行
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
try {
|
try {
|
||||||
// Android 7+ 需要给出 URI 权限(FileProvider),Expo‑Intent‑Launcher 已经在内部使用了
|
// FLAG_ACTIVITY_NEW_TASK = 0x10000000 (1)
|
||||||
|
// FLAG_GRANT_READ_URI_PERMISSION = 0x00000010
|
||||||
|
const flags = 1 | 0x00000010; // 1 | 16
|
||||||
|
|
||||||
await IntentLauncher.startActivityAsync('android.intent.action.VIEW', {
|
await IntentLauncher.startActivityAsync('android.intent.action.VIEW', {
|
||||||
data: fileUri,
|
data: contentUri, // 必须是 content://
|
||||||
type: ANDROID_MIME_TYPE,
|
type: ANDROID_MIME_TYPE, // application/vnd.android.package-archive
|
||||||
flags: 1, // FLAG_ACTIVITY_NEW_TASK
|
flags,
|
||||||
});
|
});
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
// 常见错误:没有“未知来源”权限、或没有安装包管理器
|
// 统一错误提示
|
||||||
if (e.message?.includes('Activity not found')) {
|
if (e.message?.includes('Activity not found')) {
|
||||||
Toast.show({
|
Toast.show({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@@ -215,7 +212,7 @@ class UpdateService {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// iOS 是不支持的,直接提示用户
|
// iOS 设备不支持直接安装 APK
|
||||||
Toast.show({
|
Toast.show({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
text1: '安装失败',
|
text1: '安装失败',
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ const useHomeStore = create<HomeState>((set, get) => ({
|
|||||||
errorMessage = "请点击右上角设置按钮,配置您的服务器地址";
|
errorMessage = "请点击右上角设置按钮,配置您的服务器地址";
|
||||||
} else if (err.message === "UNAUTHORIZED") {
|
} else if (err.message === "UNAUTHORIZED") {
|
||||||
errorMessage = "认证失败,请重新登录";
|
errorMessage = "认证失败,请重新登录";
|
||||||
|
useAuthStore.setState({ isLoggedIn: false, isLoginModalVisible: true });
|
||||||
} else if (err.message.includes("Network")) {
|
} else if (err.message.includes("Network")) {
|
||||||
errorMessage = "网络连接失败,请检查网络连接";
|
errorMessage = "网络连接失败,请检查网络连接";
|
||||||
} else if (err.message.includes("timeout")) {
|
} else if (err.message.includes("timeout")) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { create } from "zustand";
|
|||||||
import { SettingsManager } from "@/services/storage";
|
import { SettingsManager } from "@/services/storage";
|
||||||
import { api, ServerConfig } from "@/services/api";
|
import { api, ServerConfig } from "@/services/api";
|
||||||
import { storageConfig } from "@/services/storageConfig";
|
import { storageConfig } from "@/services/storageConfig";
|
||||||
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||||
import Logger from "@/utils/Logger";
|
import Logger from "@/utils/Logger";
|
||||||
|
|
||||||
const logger = Logger.withTag('SettingsStore');
|
const logger = Logger.withTag('SettingsStore');
|
||||||
@@ -79,7 +80,8 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
|
|||||||
setVideoSource: (config) => set({ videoSource: config }),
|
setVideoSource: (config) => set({ videoSource: config }),
|
||||||
saveSettings: async () => {
|
saveSettings: async () => {
|
||||||
const { apiBaseUrl, m3uUrl, remoteInputEnabled, videoSource } = get();
|
const { apiBaseUrl, m3uUrl, remoteInputEnabled, videoSource } = get();
|
||||||
|
const currentSettings = await SettingsManager.get()
|
||||||
|
const currentApiBaseUrl = currentSettings.apiBaseUrl;
|
||||||
let processedApiBaseUrl = apiBaseUrl.trim();
|
let processedApiBaseUrl = apiBaseUrl.trim();
|
||||||
if (processedApiBaseUrl.endsWith("/")) {
|
if (processedApiBaseUrl.endsWith("/")) {
|
||||||
processedApiBaseUrl = processedApiBaseUrl.slice(0, -1);
|
processedApiBaseUrl = processedApiBaseUrl.slice(0, -1);
|
||||||
@@ -105,6 +107,9 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
|
|||||||
remoteInputEnabled,
|
remoteInputEnabled,
|
||||||
videoSource,
|
videoSource,
|
||||||
});
|
});
|
||||||
|
if ( currentApiBaseUrl !== processedApiBaseUrl) {
|
||||||
|
await AsyncStorage.setItem('authCookies', '');
|
||||||
|
}
|
||||||
api.setBaseUrl(processedApiBaseUrl);
|
api.setBaseUrl(processedApiBaseUrl);
|
||||||
// Also update the URL in the state so the input field shows the processed URL
|
// Also update the URL in the state so the input field shows the processed URL
|
||||||
set({ isModalVisible: false, apiBaseUrl: processedApiBaseUrl });
|
set({ isModalVisible: false, apiBaseUrl: processedApiBaseUrl });
|
||||||
|
|||||||
Reference in New Issue
Block a user