android程序?;睿?020)

公司的一個(gè)app,需要接收付款通知,用百度TTS播報(bào)。但是程序在后臺(tái),滅屏+不充電的情況下,幾分鐘后就無(wú)法響應(yīng)了。
要想app一直在后臺(tái)存活,需要做保活操作。
以前的一些保活措施已經(jīng)失效了,找了一篇靠譜的文章:
https://juejin.im/post/6844904023955341319
http://www.52im.net/thread-3033-1-1.html
這篇文章里,提供了兩種方法。
1:開啟系統(tǒng)電池白名單。
2:引導(dǎo)用戶在設(shè)置里,將app加入后臺(tái)運(yùn)行白名單。
加了這兩種方法后,經(jīng)過(guò)測(cè)試,也只能維持一個(gè)小時(shí),在別的app里,看到還加入了一項(xiàng)措施,開啟前臺(tái)服務(wù)。
試了下加入前臺(tái)服務(wù)后,基本上能一直存活了。
3:加入前臺(tái)服務(wù)。

以下實(shí)現(xiàn)這3種操作。
1:開啟系統(tǒng)電池白名單。
屏幕滅屏的時(shí)候,會(huì)將后臺(tái)的一些進(jìn)程殺死,讓電池耐用,所以需要加入這個(gè)白名單。
先在manifest里面加上權(quán)限

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

開啟白名單

public void requestIgnoreBatteryOptimizations() {
        try {
            Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.setData(Uri.parse("package:" + getContext().getPackageName()));
            startActivityForResult(intent,1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
111111.png

會(huì)彈出提示框,點(diǎn)擊允許即可。
可以判斷是否已經(jīng)開啟了白名單:

private boolean isIgnoringBatteryOptimizations() {
        boolean isIgnoring = false;
        PowerManager powerManager = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
        if (powerManager != null) {
            isIgnoring = powerManager.isIgnoringBatteryOptimizations(getContext().getPackageName());
        }
        return isIgnoring;
    }

2:引導(dǎo)用戶在設(shè)置里,將app加入后臺(tái)運(yùn)行白名單。
這一步,對(duì)用戶來(lái)說(shuō)比較復(fù)雜,需要引導(dǎo)用戶去設(shè)置里,讓app允許在后臺(tái)運(yùn)行。
因?yàn)椴煌膹S商,進(jìn)入后臺(tái)白名單的界面不一樣,需要單獨(dú)定制。
以華為為例:

public void goHuaweiSetting() {
        try {
            showActivity("com.huawei.systemmanager",
                    "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");
        } catch (Exception e) {
            showActivity("com.huawei.systemmanager",
                    "com.huawei.systemmanager.optimize.bootstart.BootStartActivity");
        }
    }
222222.png

勾選允許自啟動(dòng)和后臺(tái)活動(dòng)即可。

第一步和第二部的詳細(xì)代碼如下:(來(lái)自https://juejin.im/post/6844904023955341319
http://www.52im.net/thread-3033-1-1.html

public class MobileButlerUtil {

    private Context mContext;

    public MobileButlerUtil(Context context){
        this.mContext = context;
    }

    public boolean isHuawei() {
        if (Build.BRAND == null) {
            return false;
        } else {
            return Build.BRAND.toLowerCase().equals("huawei") || Build.BRAND.toLowerCase().equals("honor");
        }
    }

    public boolean isXiaomi() {
        return Build.BRAND != null && Build.BRAND.toLowerCase().equals("xiaomi");
    }

    public boolean isOPPO() {
        return Build.BRAND != null && Build.BRAND.toLowerCase().equals("oppo");
    }

    public boolean isVIVO() {
        return Build.BRAND != null && Build.BRAND.toLowerCase().equals("vivo");
    }

    public boolean isMeizu() {
        return Build.BRAND != null && Build.BRAND.toLowerCase().equals("meizu");
    }

    public boolean isSamsung() {
        return Build.BRAND != null && Build.BRAND.toLowerCase().equals("samsung");
    }

    public boolean isLeTV() {
        return Build.BRAND != null && Build.BRAND.toLowerCase().equals("letv");
    }

    public boolean isSmartisan() {
        return Build.BRAND != null && Build.BRAND.toLowerCase().equals("smartisan");
    }


    public void goHuaweiSetting() {
        try {
            showActivity("com.huawei.systemmanager",
                    "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");
        } catch (Exception e) {
            showActivity("com.huawei.systemmanager",
                    "com.huawei.systemmanager.optimize.bootstart.BootStartActivity");
        }
    }

    public void goXiaomiSetting() {
        showActivity("com.miui.securitycenter",
                "com.miui.permcenter.autostart.AutoStartManagementActivity");
    }

    public void goOPPOSetting() {
        try {
            showActivity("com.coloros.phonemanager");
        } catch (Exception e1) {
            try {
                showActivity("com.oppo.safe");
            } catch (Exception e2) {
                try {
                    showActivity("com.coloros.oppoguardelf");
                } catch (Exception e3) {
                    showActivity("com.coloros.safecenter");
                }
            }
        }
    }

    public void goVIVOSetting() {
        showActivity("com.iqoo.secure");
    }

    public void goMeizuSetting() {
        showActivity("com.meizu.safe");
    }

    public void goSamsungSetting() {
        try {
            showActivity("com.samsung.android.sm_cn");
        } catch (Exception e) {
            showActivity("com.samsung.android.sm");
        }
    }

    public void goLetvSetting() {
        showActivity("com.letv.android.letvsafe",
                "com.letv.android.letvsafe.AutobootManageActivity");
    }

    public void goSmartisanSetting() {
        showActivity("com.smartisanos.security");
    }

    /**
     * 跳轉(zhuǎn)到指定應(yīng)用的首頁(yè)
     */
    public void showActivity(@NonNull String packageName) {
        Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(packageName);
        mContext.startActivity(intent);
    }

    /**
     * 跳轉(zhuǎn)到指定應(yīng)用的指定頁(yè)面
     */
    public void showActivity(@NonNull String packageName, @NonNull String activityDir) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(packageName, activityDir));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
    }


}
public class PermissionSetting extends BaseFragment implements View.OnClickListener {


    @BindView(R.id.battery_white)
    TextView batteryWhite;

    @BindView(R.id.operation_permission)
    TextView operationPermission;

    @BindView(R.id.iv_goback)
    TextView goBack;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.battery_white:
                //加入電池白名單
                requestIgnoreBatteryOptimizations();
                break;
            case R.id.operation_permission:
                checkPermission();//設(shè)置允許后臺(tái)活動(dòng)
                break;
            case R.id.iv_goback:
                pop();
                break;
        }

    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private boolean isIgnoringBatteryOptimizations() {
        boolean isIgnoring = false;
        PowerManager powerManager = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
        if (powerManager != null) {
            isIgnoring = powerManager.isIgnoringBatteryOptimizations(getContext().getPackageName());
        }
        return isIgnoring;
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    public void requestIgnoreBatteryOptimizations() {
        try {
            Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.setData(Uri.parse("package:" + getContext().getPackageName()));
            startActivityForResult(intent,1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1) {
            if(isIgnoringBatteryOptimizations()){
                batteryWhite.setText("已開啟");
                batteryWhite.setBackground(null);
                batteryWhite.setEnabled(false);
            }
        }
    }

    public void checkPermission(){
        MobileButlerUtil mobileButlerUtil = new MobileButlerUtil(getContext());
        final PromptPopup promptPopup = new PromptPopup(getContext())
                .setContent("為了接收到賬通知,請(qǐng)去設(shè)置易掌管app允許在后臺(tái)活動(dòng)")
                .withConfirmClick(v -> {
                    if(mobileButlerUtil.isHuawei()){
                        mobileButlerUtil.goHuaweiSetting();
                    }else if(mobileButlerUtil.isXiaomi()){
                        mobileButlerUtil.goXiaomiSetting();
                    }else if(mobileButlerUtil.isOPPO()){
                        mobileButlerUtil.goOPPOSetting();
                    }else if(mobileButlerUtil.isVIVO()){
                        mobileButlerUtil.goVIVOSetting();
                    }else if(mobileButlerUtil.isMeizu()){
                        mobileButlerUtil.goMeizuSetting();
                    }else if(mobileButlerUtil.isSamsung()){
                        mobileButlerUtil.goSamsungSetting();
                    }else if(mobileButlerUtil.isLeTV()){
                        mobileButlerUtil.goLetvSetting();
                    }else if(mobileButlerUtil.isSmartisan()){
                        mobileButlerUtil.goSmartisanSetting();
                    }
                }, true);
        promptPopup.showPopupWindow();
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    public void onLazyInitView(@Nullable Bundle savedInstanceState) {
        super.onLazyInitView(savedInstanceState);
        ImmersionBar.with(this).titleBar(R.id.ly_title_bar).autoDarkModeEnable(true).statusBarColor(R.color.bar_grey).init();
        batteryWhite.setOnClickListener(this);
        operationPermission.setOnClickListener(this);
        goBack.setOnClickListener(this);

        if(isIgnoringBatteryOptimizations()){
            batteryWhite.setText("已開啟");
            batteryWhite.setBackground(null);
            batteryWhite.setEnabled(false);
        }
    }



    @Override
    protected int getLayoutId() {
        return R.layout.permission_setting;
    }
}

關(guān)鍵的第三步:開啟前臺(tái)服務(wù)。

//開啟前臺(tái)服務(wù)
        intent = new Intent(MainActivity.this, WhiteService.class);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {//8.0以上的開啟方式不同
            startForegroundService(intent);
        } else {
            startService(intent);
        }

注意在onDestroy時(shí),關(guān)閉服務(wù):

//關(guān)閉前臺(tái)服務(wù)
        stopService(intent);

服務(wù):

public class WhiteService extends Service {

    private static final String TAG = WhiteService.class.getSimpleName();
    private static final int NOTIFICATION_FLAG =0X11;
    private static final String CHANNEL_ONE_ID = "NOTIFY_ID";
    private static final String CHANNEL_ONE_NAME = "PUSH_NOTIFY_NAME";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 在Android進(jìn)行通知處理,首先需要重系統(tǒng)哪里獲得通知管理器NotificationManager,它是一個(gè)系統(tǒng)Service。
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // 設(shè)置點(diǎn)擊通知跳轉(zhuǎn)的Intent
        Intent nfIntent = new Intent(this, MainActivity.class);
        // 設(shè)置 延遲Intent
        // 最后一個(gè)參數(shù)可以為PendingIntent.FLAG_CANCEL_CURRENT 或者 PendingIntent.FLAG_UPDATE_CURRENT
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, nfIntent, 0);

        //構(gòu)建一個(gè)Notification構(gòu)造器
        Notification.Builder builder = new Notification.Builder(this.getApplicationContext());

        //適配8.0service
        NotificationChannel mChannel = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            mChannel = new NotificationChannel(CHANNEL_ONE_ID, CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(mChannel);
            builder.setChannelId(CHANNEL_ONE_ID);
        }

        builder.setContentIntent(pendingIntent)   // 設(shè)置點(diǎn)擊跳轉(zhuǎn)界面
                .setLargeIcon(BitmapFactory.decodeResource(this.getResources(),
                        R.drawable.login_logo)) // 設(shè)置下拉列表中的圖標(biāo)(大圖標(biāo))
                .setTicker("您有一個(gè)notification")// statusBar上的提示
                .setContentTitle("xxxapp正在后臺(tái)運(yùn)行") // 設(shè)置下拉列表里的標(biāo)題
                .setSmallIcon(R.drawable.login_logo) // 設(shè)置狀態(tài)欄內(nèi)的小圖標(biāo)24X24
                .setContentText("為了能正常收到付款通知,請(qǐng)不要結(jié)束應(yīng)用。") // 設(shè)置詳細(xì)內(nèi)容
                .setContentIntent(pendingIntent) // 設(shè)置點(diǎn)擊跳轉(zhuǎn)的界面
                .setWhen(System.currentTimeMillis()) // 設(shè)置該通知發(fā)生的時(shí)間
                .setDefaults(Notification.DEFAULT_VIBRATE) //默認(rèn)震動(dòng)方式
                .setPriority(Notification.PRIORITY_HIGH);   //優(yōu)先級(jí)高

        Notification notification = builder.build(); // 獲取構(gòu)建好的Notification
        notification.defaults = Notification.DEFAULT_SOUND; //設(shè)置為默認(rèn)的聲音
        notification.flags |= Notification.FLAG_AUTO_CANCEL; // FLAG_AUTO_CANCEL表明當(dāng)通知被用戶點(diǎn)擊時(shí),通知將被清除。
        notification.flags |= Notification.FLAG_ONGOING_EVENT; //將此通知放到通知欄的"Ongoing"即"正在運(yùn)行"組中
        notification.flags |= Notification.FLAG_NO_CLEAR; //表明在點(diǎn)擊了通知欄中的"清除通知"后,此通知不清除,常與FLAG_ONGOING_EVENT一起使用


        //manager.notify(NOTIFICATION_FLAG, notification);
        // 啟動(dòng)前臺(tái)服務(wù)
        // 參數(shù)一:唯一的通知標(biāo)識(shí);參數(shù)二:通知消息。
        startForeground(NOTIFICATION_FLAG, notification);// 開始前臺(tái)服務(wù)
        Log.d(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 停止前臺(tái)服務(wù)--參數(shù):表示是否移除之前的通知
        stopForeground(true);
        Log.d(TAG, "onDestroy");
    }

}

參考自:
https://blog.csdn.net/weixin_37577039/article/details/80041624
https://blog.csdn.net/o279642707/article/details/82352431
http://www.itdecent.cn/p/cb8426620e74

實(shí)現(xiàn)的以上三步,程序應(yīng)該能在后臺(tái)存活很久了。

另外,針對(duì)第二步,引導(dǎo)用戶操作,對(duì)用戶而言過(guò)于復(fù)雜,看到有人提到可以用android無(wú)障礙模式自動(dòng)加白,如果有人做出來(lái)了,可以分享一下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容