mirror of
https://github.com/ikun0014/lx-music-mobile.git
synced 2025-07-04 15:38:56 +08:00
添加是否忽略电池优化检查
This commit is contained in:
parent
68b22dbd3d
commit
a6a8053826
@ -9,6 +9,7 @@
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
|
@ -0,0 +1,40 @@
|
||||
package cn.toside.music.mobile.utils;
|
||||
|
||||
import static android.content.Context.POWER_SERVICE;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
public class BatteryOptimizationUtil {
|
||||
public static boolean isIgnoringBatteryOptimization(Context context, String packageName) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
|
||||
return powerManager.isIgnoringBatteryOptimizations(packageName);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean requestIgnoreBatteryOptimization(Context context, String packageName) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
@SuppressLint("BatteryLife") Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
||||
intent.setData(Uri.parse("package:" + packageName));
|
||||
try {
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
} catch (Exception ignored) {}
|
||||
try {
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
} catch (Exception ignored) {}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -255,7 +255,7 @@ public class UtilsModule extends ReactContextBaseJavaModule {
|
||||
|
||||
// https://blog.51cto.com/u_15298568/3121162
|
||||
@ReactMethod
|
||||
public void openNotificationPermissionActivity() {
|
||||
public void openNotificationPermissionActivity(Promise promise) {
|
||||
Intent intent = new Intent();
|
||||
String packageName = reactContext.getApplicationContext().getPackageName();
|
||||
|
||||
@ -268,7 +268,12 @@ public class UtilsModule extends ReactContextBaseJavaModule {
|
||||
intent.putExtra("app_uid", reactContext.getApplicationContext().getApplicationInfo().uid);
|
||||
}
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
try {
|
||||
reactContext.startActivity(intent);
|
||||
promise.resolve(true);
|
||||
} catch (Exception ignore) {
|
||||
promise.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
@ -371,5 +376,15 @@ public class UtilsModule extends ReactContextBaseJavaModule {
|
||||
params.putInt("height", rect.height());
|
||||
promise.resolve(params);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void isIgnoringBatteryOptimization(Promise promise) {
|
||||
promise.resolve(BatteryOptimizationUtil.isIgnoringBatteryOptimization(reactContext.getApplicationContext(), reactContext.getPackageName()));
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void requestIgnoreBatteryOptimization(Promise promise) {
|
||||
promise.resolve(BatteryOptimizationUtil.requestIgnoreBatteryOptimization(reactContext.getApplicationContext(), reactContext.getPackageName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,3 @@
|
||||
落雪提前祝大家中秋快乐~🥮😘!
|
||||
|
||||
### 优化
|
||||
|
||||
- 通过歌曲菜单添加不喜欢歌曲时需要二次确认防止手抖
|
||||
- 减慢歌词详情页歌词滚动速度
|
||||
- 更改应用窗口大小获取方式,尝试解决在某些设备上的背景、弹出菜单显示问题
|
||||
- 优化同步功能错误消息提示,因同步服务版本不匹配导致的连接失败现在将区分提示
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复横屏状态下的歌词滚动位置计算问题
|
||||
- 修复切歌时歌词激活行的重置问题
|
||||
- 修复更新翻译歌词、罗马音歌词设置后需重启应用才生效的问题,现在更新设置后会立即生效
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新 React native 到 v0.72.5
|
||||
- 添加是否忽略电池优化检查,用于提醒用户添加白名单,确保APP后台播放稳定性
|
||||
|
@ -56,6 +56,7 @@ export const storageDataPrefix = {
|
||||
syncHostHistory: '@sync_host_history',
|
||||
|
||||
notificationTipEnable: '@notification_tip_enable',
|
||||
ignoringBatteryOptimizationTipEnable: '@ignoring_battery_optimization_tip_enable',
|
||||
|
||||
searchHistoryList: '@search_history_list',
|
||||
listUpdateInfo: '@list_update_info',
|
||||
|
@ -8,6 +8,7 @@ import BackgroundTimer from 'react-native-background-timer'
|
||||
import playerState from '@/store/player/state'
|
||||
import settingState from '@/store/setting/state'
|
||||
import { onScreenStateChange } from '@/utils/nativeModules/utils'
|
||||
import { AppState } from 'react-native'
|
||||
|
||||
const delaySavePlayInfo = throttleBackgroundTimer(() => {
|
||||
void savePlayInfo({
|
||||
@ -158,6 +159,10 @@ export default () => {
|
||||
} else clearUpdateTimeout()
|
||||
}
|
||||
|
||||
// 修复在某些设备上屏幕状态改变事件未触发导致的进度条未更新的问题
|
||||
AppState.addEventListener('change', (state) => {
|
||||
if (state == 'active' && !isScreenOn) handleScreenStateChanged('ON')
|
||||
})
|
||||
|
||||
global.app_event.on('play', handlePlay)
|
||||
global.app_event.on('pause', handlePause)
|
||||
|
@ -24,7 +24,7 @@ import { requestMsg } from '@/utils/message'
|
||||
import { getRandom } from '@/utils/common'
|
||||
import { filterList } from './utils'
|
||||
import BackgroundTimer from 'react-native-background-timer'
|
||||
import { checkNotificationPermission } from '@/utils/tools'
|
||||
import { checkIgnoringBatteryOptimization, checkNotificationPermission } from '@/utils/tools'
|
||||
|
||||
// import { checkMusicFileAvailable } from '@renderer/utils/music'
|
||||
|
||||
@ -180,6 +180,7 @@ const handleRestorePlay = async(restorePlayInfo: LX.Player.SavedPlayInfo) => {
|
||||
const handlePlay = async() => {
|
||||
if (!isInitialized()) {
|
||||
await checkNotificationPermission()
|
||||
void checkIgnoringBatteryOptimization()
|
||||
await playerInitial({
|
||||
volume: settingState.setting['player.volume'],
|
||||
playRate: settingState.setting['player.playbackRate'],
|
||||
|
@ -2,6 +2,7 @@
|
||||
"add_to": "Add to...",
|
||||
"agree": "Agree",
|
||||
"agree_go": "To turn on",
|
||||
"agree_to": "Go to settings",
|
||||
"back": "Back",
|
||||
"back_home": "Back",
|
||||
"cancel": "Cancel",
|
||||
@ -39,6 +40,8 @@
|
||||
"dislike": "Dislike",
|
||||
"duplicate_list_tip": "You have previously favorited the list [{name}], do you want to update the songs?",
|
||||
"exit_app_tip": "Are you sure you want to quit the app?",
|
||||
"ignoring_battery_optimization_check_tip": "LX Music is not on the list of ignored battery optimization, which may cause the problem of being suspended by the system when playing music in the background. Do you want to add LX Music to the whitelist?",
|
||||
"ignoring_battery_optimization_check_title": "Background running permission setting reminder",
|
||||
"input_error": "Don't input indiscriminately 😡",
|
||||
"list_add_btn_title": "Add the song(s) to {name}",
|
||||
"list_add_tip_exists": "This song already exists in the list, don't click me again~😡",
|
||||
|
@ -2,6 +2,7 @@
|
||||
"add_to": "添加到...",
|
||||
"agree": "行行行",
|
||||
"agree_go": "去开启",
|
||||
"agree_to": "去设置",
|
||||
"back": "返回",
|
||||
"back_home": "返回桌面",
|
||||
"cancel": "取消",
|
||||
@ -39,6 +40,8 @@
|
||||
"dislike": "不喜欢",
|
||||
"duplicate_list_tip": "你之前已收藏过该列表 [{name}],是否需要更新里面的歌曲?",
|
||||
"exit_app_tip": "确定要退出应用吗?",
|
||||
"ignoring_battery_optimization_check_tip": "LX Music没有在忽略电池优化的名单中,这可能会导致在后台播放音乐时被系统暂停的问题,是否将LX Music加入该白名单中?",
|
||||
"ignoring_battery_optimization_check_title": "后台运行权限设置提醒",
|
||||
"input_error": "不要乱输好吧😡",
|
||||
"list_add_btn_title": "把该歌曲添加到 {name}",
|
||||
"list_add_tip_exists": "列表已经存在这首歌啦,不要再点我啦~😡",
|
||||
|
@ -5,7 +5,7 @@ import { StyleSheet, View, InteractionManager } from 'react-native'
|
||||
|
||||
import SubTitle from '../../components/SubTitle'
|
||||
import Button from '../../components/Button'
|
||||
import { toast, resetNotificationPermissionCheck, confirmDialog } from '@/utils/tools'
|
||||
import { toast, resetNotificationPermissionCheck, confirmDialog, resetIgnoringBatteryOptimizationCheck } from '@/utils/tools'
|
||||
import { getAppCacheSize, clearAppCache } from '@/utils/nativeModules/cache'
|
||||
import { sizeFormate } from '@/utils'
|
||||
import { useI18n } from '@/lang'
|
||||
@ -39,6 +39,7 @@ export default memo(() => {
|
||||
clearAppCache(),
|
||||
clearMusicUrl(),
|
||||
resetNotificationPermissionCheck(),
|
||||
resetIgnoringBatteryOptimizationCheck(),
|
||||
]).then(() => {
|
||||
toast(t('setting_other_cache_clear_success_tip'))
|
||||
}).finally(() => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { NativeEventEmitter, NativeModules } from 'react-native'
|
||||
import { AppState, NativeEventEmitter, NativeModules } from 'react-native'
|
||||
|
||||
const { UtilsModule } = NativeModules
|
||||
|
||||
@ -29,7 +29,20 @@ export const getDeviceName = async(): Promise<string> => {
|
||||
|
||||
export const isNotificationsEnabled = UtilsModule.isNotificationsEnabled as () => Promise<boolean>
|
||||
|
||||
export const openNotificationPermissionActivity = UtilsModule.openNotificationPermissionActivity as () => Promise<void>
|
||||
export const requestNotificationPermission = async() => new Promise<boolean>((resolve) => {
|
||||
let subscription = AppState.addEventListener('change', (state) => {
|
||||
if (state != 'active') return
|
||||
subscription.remove()
|
||||
setTimeout(() => {
|
||||
void isNotificationsEnabled().then(resolve)
|
||||
}, 1000)
|
||||
})
|
||||
UtilsModule.openNotificationPermissionActivity().then((result: boolean) => {
|
||||
if (result) return
|
||||
subscription.remove()
|
||||
resolve(false)
|
||||
})
|
||||
})
|
||||
|
||||
export const shareText = async(shareTitle: string, title: string, text: string): Promise<void> => {
|
||||
UtilsModule.shareText(shareTitle, title, text)
|
||||
@ -71,3 +84,22 @@ export const onWindowSizeChange = (callback: (size: { width: number, height: num
|
||||
eventListener.remove()
|
||||
}
|
||||
}
|
||||
|
||||
export const isIgnoringBatteryOptimization = async(): Promise<boolean> => {
|
||||
return UtilsModule.isIgnoringBatteryOptimization()
|
||||
}
|
||||
|
||||
export const requestIgnoreBatteryOptimization = async() => new Promise<boolean>((resolve) => {
|
||||
let subscription = AppState.addEventListener('change', (state) => {
|
||||
if (state != 'active') return
|
||||
subscription.remove()
|
||||
setTimeout(() => {
|
||||
void isIgnoringBatteryOptimization().then(resolve)
|
||||
}, 1000)
|
||||
})
|
||||
UtilsModule.requestIgnoreBatteryOptimization().then((result: boolean) => {
|
||||
if (result) return
|
||||
subscription.remove()
|
||||
resolve(false)
|
||||
})
|
||||
})
|
||||
|
@ -4,7 +4,7 @@ import Clipboard from '@react-native-clipboard/clipboard'
|
||||
import { storageDataPrefix } from '@/config/constant'
|
||||
import { gzipFile, unGzipFile } from '@/utils/nativeModules/gzip'
|
||||
import { temporaryDirectoryPath, unlink } from '@/utils/fs'
|
||||
import { getSystemLocales, isNotificationsEnabled, openNotificationPermissionActivity, readFile, shareText, writeFile } from '@/utils/nativeModules/utils'
|
||||
import { getSystemLocales, isIgnoringBatteryOptimization, isNotificationsEnabled, requestNotificationPermission, readFile, requestIgnoreBatteryOptimization, shareText, writeFile } from '@/utils/nativeModules/utils'
|
||||
import musicSdk from '@/utils/musicSdk'
|
||||
import { getData, removeData, saveData } from '@/plugins/storage'
|
||||
import BackgroundTimer from 'react-native-background-timer'
|
||||
@ -202,6 +202,7 @@ export const checkNotificationPermission = async() => {
|
||||
if (isHide != null) return
|
||||
const enabled = await isNotificationsEnabled()
|
||||
if (enabled) return
|
||||
return new Promise<void>((resolve) => {
|
||||
Alert.alert(
|
||||
global.i18n.t('notifications_check_title'),
|
||||
global.i18n.t('notifications_check_tip'),
|
||||
@ -211,26 +212,79 @@ export const checkNotificationPermission = async() => {
|
||||
onPress: () => {
|
||||
void saveData(storageDataPrefix.notificationTipEnable, '1')
|
||||
toast(global.i18n.t('disagree_tip'))
|
||||
resolve()
|
||||
},
|
||||
},
|
||||
{
|
||||
text: global.i18n.t('disagree'),
|
||||
onPress: () => {
|
||||
toast(global.i18n.t('disagree_tip'))
|
||||
resolve()
|
||||
},
|
||||
},
|
||||
{
|
||||
text: global.i18n.t('agree_go'),
|
||||
onPress: () => {
|
||||
void openNotificationPermissionActivity()
|
||||
requestAnimationFrame(() => {
|
||||
void requestNotificationPermission().then((result) => {
|
||||
if (!result) toast(global.i18n.t('disagree_tip'))
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const checkIgnoringBatteryOptimization = async() => {
|
||||
const isHide = await getData(storageDataPrefix.ignoringBatteryOptimizationTipEnable)
|
||||
if (isHide != null) return
|
||||
const enabled = await isIgnoringBatteryOptimization()
|
||||
if (enabled) return
|
||||
return new Promise<void>((resolve) => {
|
||||
Alert.alert(
|
||||
global.i18n.t('ignoring_battery_optimization_check_title'),
|
||||
global.i18n.t('ignoring_battery_optimization_check_tip'),
|
||||
[
|
||||
{
|
||||
text: global.i18n.t('never_show'),
|
||||
onPress: () => {
|
||||
void saveData(storageDataPrefix.ignoringBatteryOptimizationTipEnable, '1')
|
||||
toast(global.i18n.t('disagree_tip'))
|
||||
resolve()
|
||||
},
|
||||
},
|
||||
{
|
||||
text: global.i18n.t('disagree'),
|
||||
onPress: () => {
|
||||
toast(global.i18n.t('disagree_tip'))
|
||||
resolve()
|
||||
},
|
||||
},
|
||||
{
|
||||
text: global.i18n.t('agree_to'),
|
||||
onPress: () => {
|
||||
requestAnimationFrame(() => {
|
||||
void requestIgnoreBatteryOptimization().then((result) => {
|
||||
if (!result) toast(global.i18n.t('disagree_tip'))
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
})
|
||||
}
|
||||
export const resetNotificationPermissionCheck = async() => {
|
||||
return removeData(storageDataPrefix.notificationTipEnable)
|
||||
}
|
||||
export const resetIgnoringBatteryOptimizationCheck = async() => {
|
||||
return removeData(storageDataPrefix.ignoringBatteryOptimizationTipEnable)
|
||||
}
|
||||
|
||||
export const shareMusic = (shareType: LX.ShareType, downloadFileName: LX.AppSetting['download.fileName'], musicInfo: LX.Music.MusicInfo) => {
|
||||
const name = musicInfo.name
|
||||
|
Loading…
x
Reference in New Issue
Block a user