Mam Huawei P8 z Androidem 5.0, którego używam do testowania aplikacji. Aplikacja musi działać w tle, ponieważ śledzi regiony BLE.
Odkryłem, że Huawei ma wbudowaną „funkcję” o nazwie Chronione aplikacje, do której można uzyskać dostęp z ustawień telefonu (Menedżer baterii> Chronione aplikacje). Dzięki temu wybrane aplikacje będą działać po wyłączeniu ekranu.
Rozsądnie dla Huawei, ale niestety dla mnie wygląda na to, że to opt-in, czyli aplikacje są domyślnie wyłączone i musisz je ręcznie wstawiać. To nie jest showstopper, ponieważ mogę doradzić użytkownikom w FAQ lub wydrukować dokumentację dotyczącą poprawki, ale niedawno zainstalowałem Tindera (w celach badawczych!) i zauważyłem, że został automatycznie umieszczony na liście chronionych.
Czy ktoś wie, jak mogę to zrobić dla mojej aplikacji? Czy jest to ustawienie w manifeście? Czy jest to coś, co Huawei udostępnił dla Tindera, ponieważ jest to popularna aplikacja?
źródło
Odpowiedzi:
if("huawei".equalsIgnoreCase(android.os.Build.MANUFACTURER) && !sp.getBoolean("protected",false)) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.huawei_headline).setMessage(R.string.huawei_text) .setPositiveButton(R.string.go_to_protected, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { Intent intent = new Intent(); intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")); startActivity(intent); sp.edit().putBoolean("protected",true).commit(); } }).create().show(); }
źródło
ComponentName("com.asus.mobilemanager","com.asus.mobilemanager.autostart.AutoStartActivity"));
sp.edit().putBoolean("protected",true).commit();
ponieważ rozumiem, że w tym miejscu zmieniasz wartość na chronioną, prawda?Manifest nie zawiera ustawienia, a Huawei włączył Tinder, ponieważ jest to popularna aplikacja. Nie ma sposobu, aby dowiedzieć się, czy aplikacje są chronione.
Zresztą kiedyś
ifHuaweiAlert()
wonCreate()
pokazaćAlertDialog
:private void ifHuaweiAlert() { final SharedPreferences settings = getSharedPreferences("ProtectedApps", MODE_PRIVATE); final String saveIfSkip = "skipProtectedAppsMessage"; boolean skipMessage = settings.getBoolean(saveIfSkip, false); if (!skipMessage) { final SharedPreferences.Editor editor = settings.edit(); Intent intent = new Intent(); intent.setClassName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity"); if (isCallable(intent)) { final AppCompatCheckBox dontShowAgain = new AppCompatCheckBox(this); dontShowAgain.setText("Do not show again"); dontShowAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { editor.putBoolean(saveIfSkip, isChecked); editor.apply(); } }); new AlertDialog.Builder(this) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle("Huawei Protected Apps") .setMessage(String.format("%s requires to be enabled in 'Protected Apps' to function properly.%n", getString(R.string.app_name))) .setView(dontShowAgain) .setPositiveButton("Protected Apps", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { huaweiProtectedApps(); } }) .setNegativeButton(android.R.string.cancel, null) .show(); } else { editor.putBoolean(saveIfSkip, true); editor.apply(); } } } private boolean isCallable(Intent intent) { List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; } private void huaweiProtectedApps() { try { String cmd = "am start -n com.huawei.systemmanager/.optimize.process.ProtectActivity"; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { cmd += " --user " + getUserSerial(); } Runtime.getRuntime().exec(cmd); } catch (IOException ignored) { } } private String getUserSerial() { //noinspection ResourceType Object userManager = getSystemService("user"); if (null == userManager) return ""; try { Method myUserHandleMethod = android.os.Process.class.getMethod("myUserHandle", (Class<?>[]) null); Object myUserHandle = myUserHandleMethod.invoke(android.os.Process.class, (Object[]) null); Method getSerialNumberForUser = userManager.getClass().getMethod("getSerialNumberForUser", myUserHandle.getClass()); Long userSerial = (Long) getSerialNumberForUser.invoke(userManager, myUserHandle); if (userSerial != null) { return String.valueOf(userSerial); } else { return ""; } } catch (NoSuchMethodException | IllegalArgumentException | InvocationTargetException | IllegalAccessException ignored) { } return ""; }
źródło
+1 dla Pierre'a za świetne rozwiązanie, które działa dla wielu producentów urządzeń (Huawei, asus, oppo ...).
Chciałem użyć jego kodu w mojej aplikacji na Androida, która jest napisana w Javie. Mój kod zainspirowałem się odpowiedziami Pierre'a i Aiuspaktyn .
import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Build; import android.support.v7.widget.AppCompatCheckBox; import android.widget.CompoundButton; import java.util.List; public class Utils { public static void startPowerSaverIntent(Context context) { SharedPreferences settings = context.getSharedPreferences("ProtectedApps", Context.MODE_PRIVATE); boolean skipMessage = settings.getBoolean("skipProtectedAppCheck", false); if (!skipMessage) { final SharedPreferences.Editor editor = settings.edit(); boolean foundCorrectIntent = false; for (Intent intent : Constants.POWERMANAGER_INTENTS) { if (isCallable(context, intent)) { foundCorrectIntent = true; final AppCompatCheckBox dontShowAgain = new AppCompatCheckBox(context); dontShowAgain.setText("Do not show again"); dontShowAgain.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { editor.putBoolean("skipProtectedAppCheck", isChecked); editor.apply(); } }); new AlertDialog.Builder(context) .setTitle(Build.MANUFACTURER + " Protected Apps") .setMessage(String.format("%s requires to be enabled in 'Protected Apps' to function properly.%n", context.getString(R.string.app_name))) .setView(dontShowAgain) .setPositiveButton("Go to settings", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { context.startActivity(intent); } }) .setNegativeButton(android.R.string.cancel, null) .show(); break; } } if (!foundCorrectIntent) { editor.putBoolean("skipProtectedAppCheck", true); editor.apply(); } } } private static boolean isCallable(Context context, Intent intent) { try { if (intent == null || context == null) { return false; } else { List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; } } catch (Exception ignored) { return false; } } }
}
import android.content.ComponentName; import android.content.Intent; import java.util.Arrays; import java.util.List; public class Constants { //updated the POWERMANAGER_INTENTS 26/06/2019 static final List<Intent> POWERMANAGER_INTENTS = Arrays.asList( new Intent().setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")), new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")), new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")), new Intent().setComponent(new ComponentName("com.huawei.systemmanager", Build.VERSION.SDK_INT >= Build.VERSION_CODES.P? "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity": "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")), new Intent().setComponent(new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity")), new Intent().setComponent(new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerSaverModeActivity")), new Intent().setComponent(new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerConsumptionActivity")), new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")), Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")).setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).setData(Uri.parse("package:"+ MyApplication.getContext().getPackageName())) : null, new Intent().setComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")), new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")), new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")), new Intent().setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")), new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.entry.FunctionActivity")), new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.autostart.AutoStartActivity")), new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")) .setData(android.net.Uri.parse("mobilemanager://function/entry/AutoStart")), new Intent().setComponent(new ComponentName("com.meizu.safe", "com.meizu.safe.security.SHOW_APPSEC")).addCategory(Intent.CATEGORY_DEFAULT).putExtra("packageName", BuildConfig.APPLICATION_ID) ); }
Dodaj następujące uprawnienia w swoim
Android.Manifest
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/> <uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE"/> <uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT"/>
Mam nadzieję, że to komuś pomoże.
źródło
Rozwiązanie dla wszystkich urządzeń (Xamarin.Android)
Stosowanie:
MainActivity => protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); MyUtils.StartPowerSaverIntent(this); }
public class MyUtils { private const string SKIP_INTENT_CHECK = "skipAppListMessage"; private static List<Intent> POWERMANAGER_INTENTS = new List<Intent>() { new Intent().SetComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")), new Intent().SetComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")), new Intent().SetComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")), new Intent().SetComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")), new Intent().SetComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")), new Intent().SetComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")), new Intent().SetComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")), new Intent().SetComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")), new Intent().SetComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")), new Intent().SetComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")), new Intent().SetComponent(new ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")), new Intent().SetComponent(new ComponentName("com.htc.pitroad", "com.htc.pitroad.landingpage.activity.LandingPageActivity")), new Intent().SetComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.autostart.AutoStartActivity")), new Intent().SetComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.entry.FunctionActivity")).SetData(Android.Net.Uri.Parse("mobilemanager://function/entry/AutoStart")), new Intent().SetComponent(new ComponentName("com.dewav.dwappmanager", "com.dewav.dwappmanager.memory.SmartClearupWhiteList")) }; public static void StartPowerSaverIntent(Context context) { ISharedPreferences settings = context.GetSharedPreferences("ProtectedApps", FileCreationMode.Private); bool skipMessage = settings.GetBoolean(SKIP_INTENT_CHECK, false); if (!skipMessage) { bool HasIntent = false; ISharedPreferencesEditor editor = settings.Edit(); foreach (Intent intent in POWERMANAGER_INTENTS) { if (context.PackageManager.ResolveActivity(intent, PackageInfoFlags.MatchDefaultOnly) != null) { var dontShowAgain = new Android.Support.V7.Widget.AppCompatCheckBox(context); dontShowAgain.Text = "Do not show again"; dontShowAgain.CheckedChange += (object sender, CompoundButton.CheckedChangeEventArgs e) => { editor.PutBoolean(SKIP_INTENT_CHECK, e.IsChecked); editor.Apply(); }; new AlertDialog.Builder(context) .SetIcon(Android.Resource.Drawable.IcDialogAlert) .SetTitle(string.Format("Add {0} to list", context.GetString(Resource.String.app_name))) .SetMessage(string.Format("{0} requires to be enabled/added in the list to function properly.\n", context.GetString(Resource.String.app_name))) .SetView(dontShowAgain) .SetPositiveButton("Go to settings", (o, d) => context.StartActivity(intent)) .SetNegativeButton(Android.Resource.String.Cancel, (o, d) => { }) .Show(); HasIntent = true; break; } } if (!HasIntent) { editor.PutBoolean(SKIP_INTENT_CHECK, true); editor.Apply(); } } } }
Dodaj następujące uprawnienia w swoim
Android.Manifest
<uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE"/> <uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT"/>
Aby znaleźć działanie urządzenia, którego nie ma na liście, po prostu użyj następującej metody, aby znaleźć prawidłowe działanie do otwarcia dla użytkownika
DO#
public static void LogDeviceBrandActivities(Context context) { var Brand = Android.OS.Build.Brand?.ToLower()?.Trim() ?? ""; var Manufacturer = Android.OS.Build.Manufacturer?.ToLower()?.Trim() ?? ""; var apps = context.PackageManager.GetInstalledPackages(PackageInfoFlags.Activities); foreach (PackageInfo pi in apps.OrderBy(n => n.PackageName)) { if (pi.PackageName.ToLower().Contains(Brand) || pi.PackageName.ToLower().Contains(Manufacturer)) { var print = false; var activityInfo = ""; if (pi.Activities != null) { foreach (var activity in pi.Activities.OrderBy(n => n.Name)) { if (activity.Name.ToLower().Contains(Brand) || activity.Name.ToLower().Contains(Manufacturer)) { activityInfo += " Activity: " + activity.Name + (string.IsNullOrEmpty(activity.Permission) ? "" : " - Permission: " + activity.Permission) + "\n"; print = true; } } } if (print) { Android.Util.Log.Error("brand.activities", "PackageName: " + pi.PackageName); Android.Util.Log.Warn("brand.activities", activityInfo); } } } }
Jawa
public static void logDeviceBrandActivities(Context context) { String brand = Build.BRAND.toLowerCase(); String manufacturer = Build.MANUFACTURER.toLowerCase(); List<PackageInfo> apps = context.getPackageManager().getInstalledPackages(PackageManager.GET_ACTIVITIES); Collections.sort(apps, (a, b) -> a.packageName.compareTo(b.packageName)); for (PackageInfo pi : apps) { if (pi.packageName.toLowerCase().contains(brand) || pi.packageName.toLowerCase().contains(manufacturer)) { boolean print = false; StringBuilder activityInfo = new StringBuilder(); if (pi.activities != null && pi.activities.length > 0) { List<ActivityInfo> activities = Arrays.asList(pi.activities); Collections.sort(activities, (a, b) -> a.name.compareTo(b.name)); for (ActivityInfo ai : activities) { if (ai.name.toLowerCase().contains(brand) || ai.name.toLowerCase().contains(manufacturer)) { activityInfo.append(" Activity: ").append(ai.name) .append(ai.permission == null || ai.permission.length() == 0 ? "" : " - Permission: " + ai.permission) .append("\n"); print = true; } } } if (print) { Log.e("brand.activities", "PackageName: " + pi.packageName); Log.w("brand.activities", activityInfo.toString()); } } } }
Wykonaj podczas uruchamiania i przeszukaj plik dziennika, dodaj filtr logcat
TAG
dobrand.activities
MainActivity => protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); MyUtils.LogDeviceBrandActivities(this); }
Przykładowe dane wyjściowe:
E/brand.activities: PackageName: com.samsung.android.lool W/brand.activities: ... W/brand.activities: Activity: com.samsung.android.sm.ui.battery.AppSleepSettingActivity W/brand.activities: Activity: com.samsung.android.sm.ui.battery.BatteryActivity <-- This is the one... W/brand.activities: Activity: com.samsung.android.sm.ui.battery.BatteryActivityForCard W/brand.activities: ...
Więc nazwa komponentu będzie wyglądać następująco:
new ComponentName("<PackageName>", "<Activity>") new ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")
Jeśli obok działania jest uprawnienie,
Android.Manifest
do otwarcia działania wymagany jest następujący wpis :<uses-permission android:name="<permission>" />
Skomentuj lub edytuj nowy komponent w tej odpowiedzi. Każda pomoc będzie mi bardzo wdzięczna.
źródło
Używam rozwiązania @Aiuspaktyn, w którym brakuje części dotyczącej wykrywania zatrzymania wyświetlania okna dialogowego po ustawieniu aplikacji jako chronionej przez użytkownika. Korzystam z usługi, aby sprawdzić, czy aplikacja została zamknięta, czy nie, sprawdzając, czy istnieje.
źródło
Możesz użyć tej biblioteki, aby skierować użytkownika do chronionych aplikacji lub autostartu:
AutoStarter
Jeśli telefon obsługuje funkcję autostartu, możesz wyświetlić użytkownikowi podpowiedź, aby włączyć aplikację w tych aplikacjach
Możesz sprawdzić tą metodą:
AutoStartPermissionHelper.getInstance().isAutoStartPermissionAvailable(context)
Aby skierować użytkownika do tej strony, po prostu nazwij to:
AutoStartPermissionHelper.getInstance().getAutoStartPermission(context)
źródło
PowerMaster -> AutoStart -> Znajdź swoją aplikację w zablokowanej sekcji i zezwól
źródło