Android快捷方式解密

Android快捷方式解密

Android快捷方式作為Android設(shè)備的殺手锏技能,一直都是非常重要的一個(gè)功能,也正是如此,各種流氓App也不斷通過快捷方式霸占著這樣一個(gè)用戶入口。

同時(shí),各大國(guó)產(chǎn)ROM和Luncher的崛起,讓這個(gè)桌面之爭(zhēng)變的更加激烈。畢竟大家都只想用戶用自己的App資源,所以,現(xiàn)在各大App不僅僅是要搶占入口,同時(shí)還要和各大ROM斗智斗勇。本文將對(duì)這個(gè)快捷方式進(jìn)行深度解密,同時(shí)給出App適配各種ROM的整合方案。

本文很多地方參考了這位朋友的實(shí)現(xiàn):

https://gist.github.com/waylife/437a3d98a84f245b9582

特此表示感謝!

創(chuàng)建快捷方式之——少林派

所謂少林,是指系統(tǒng)正統(tǒng)的解決方法

天下武功出少林,天下的快捷方式都是Google給的,我們先來(lái)看看如何使用Android系統(tǒng)提供的方式來(lái)使用Android的快捷方式。

首先大家要知道各種Launcher的區(qū)別,原生的Launcher,是兩層結(jié)構(gòu),桌面是快捷方式,而進(jìn)去后的App列表是App的Launch Icon;而以小米為首的一幫ROM,參考iOS風(fēng)格,將Launcher改為了一層,即直接顯示Launch Icon。

權(quán)限設(shè)置

    <!-- 添加快捷方式 -->
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    <!-- 移除快捷方式 -->
    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
    <!-- 查詢快捷方式 -->
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />

創(chuàng)建快捷方式

創(chuàng)建快捷方式的Action:

    // Action 添加Shortcut
    public static final String ACTION_ADD_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT";

通過廣播創(chuàng)建快捷方式:

    /**
     * 添加快捷方式
     *
     * @param context      context
     * @param actionIntent 要啟動(dòng)的Intent
     * @param name         name
     */
    public static void addShortcut(Context context, Intent actionIntent, String name,
                                   boolean allowRepeat, Bitmap iconBitmap) {
        Intent addShortcutIntent = new Intent(ACTION_ADD_SHORTCUT);
        // 是否允許重復(fù)創(chuàng)建
        addShortcutIntent.putExtra("duplicate", allowRepeat);
        // 快捷方式的標(biāo)題
        addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
        // 快捷方式的圖標(biāo)
        addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, iconBitmap);
        // 快捷方式的動(dòng)作
        addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);
        context.sendBroadcast(addShortcutIntent);
    }

參數(shù)相信大家都能看得懂,只是有一點(diǎn)需要注意的,duplicate這個(gè)屬性,是設(shè)置該快捷方式是否允許多次創(chuàng)建的屬性,但是,在很多ROM上都不能成功識(shí)別,嗯,這就是我們最開始說(shuō)的快捷方式亂現(xiàn)象。

刪除快捷方式

刪除快捷方式的Action:

    // Action 移除Shortcut
    public static final String ACTION_REMOVE_SHORTCUT = "com.android.launcher.action.UNINSTALL_SHORTCUT";

通過廣播刪除快捷方式:

    /**
     * 移除快捷方式
     *
     * @param context      context
     * @param actionIntent 要啟動(dòng)的Intent
     * @param name         name
     */
    public static void removeShortcut(Context context, Intent actionIntent, String name) {
        Intent intent = new Intent(ACTION_REMOVE_SHORTCUT);
        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
//        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.putExtra("duplicate", false);
        intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);
        context.sendBroadcast(intent);
    }

參數(shù)與創(chuàng)建快捷方式的方法擊敗類似,需要注意的是,Intent.EXTRA_SHORTCUT_INTENT,與之前創(chuàng)建快捷方式的Intent必須要是同一個(gè),不然是無(wú)法刪除快捷方式的。

創(chuàng)建快捷方式之——逍遙派

所謂逍遙派,是指我們從原理來(lái)理解如何來(lái)適配各種Launcher。

原生的快捷方式添加方法,雖然是官方提供的,但在天國(guó)這樣一個(gè)怎么說(shuō)呢的國(guó)家里,基本是很難使用、適配的,也就是我們最開始說(shuō)的那些原因。下面我們先從快捷方式的整個(gè)生命周期來(lái)了解下產(chǎn)生、添加、刪除快捷方式的原理,再來(lái)思考如何實(shí)現(xiàn)多ROM、Launcher的適配。

快捷方式的存儲(chǔ)

快捷方式其實(shí)都存儲(chǔ)在Launcher的數(shù)據(jù)庫(kù)中,我們?cè)谑謾C(jī)上打開SQLite Editor打開Launcher的數(shù)據(jù)庫(kù)。

1.png

我們打開Launcher.db的favorite表,這里就是我們保存的快捷方式數(shù)據(jù):

2.png

幾個(gè)主要的字段大家基本一看就懂:title、intent、iconResource、icon,分別對(duì)應(yīng)快捷方式名稱,快捷方式intent,快捷方式圖標(biāo)來(lái)源,快捷方式圖標(biāo)二進(jìn)制數(shù)據(jù)。

快捷方式的創(chuàng)建

了解了快捷方式的存儲(chǔ)原理,我們就可以針對(duì)這個(gè)數(shù)據(jù)庫(kù)來(lái)做文章,所有的快捷方式都可以通過修改這個(gè)數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn),同時(shí)還不用太考慮兼容性問題。

對(duì)于快捷方式的創(chuàng)建,我們依然可以使用系統(tǒng)提供的方法,所以這里不再多說(shuō)。

快捷方式的判斷是否存在

前面我們說(shuō)了,通過duplicate屬性可以區(qū)分是否允許創(chuàng)建重復(fù)的快捷方式,但是,很多ROM是無(wú)法兼容到的,所以,這里我們使用查詢Launcher數(shù)據(jù)庫(kù)的方式來(lái)實(shí)現(xiàn)。

我們先來(lái)看代碼:

    /**
     * 檢查快捷方式是否存在 <br/>
     * <font color=red>注意:</font> 有些手機(jī)無(wú)法判斷是否已經(jīng)創(chuàng)建過快捷方式<br/>
     * 因此,在創(chuàng)建快捷方式時(shí),請(qǐng)?zhí)砑?lt;br/>
     * shortcutIntent.putExtra("duplicate", false);// 不允許重復(fù)創(chuàng)建<br/>
     * 最好使用{@link #isShortCutExist(Context, String, Intent)}
     * 進(jìn)行判斷,因?yàn)榭赡苡行?yīng)用生成的快捷方式名稱是一樣的的<br/>
     */
    public static boolean isShortCutExist(Context context, String title) {
        boolean result = false;
        try {
            ContentResolver cr = context.getContentResolver();
            Uri uri = getUriFromLauncher(context);
            Cursor c = cr.query(uri, new String[]{"title"}, "title=? ", new String[]{title}, null);
            if (c != null && c.getCount() > 0) {
                result = true;
            }
            if (c != null && !c.isClosed()) {
                c.close();
            }
        } catch (Exception e) {
            result = false;
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 不一定所有的手機(jī)都有效,因?yàn)閲?guó)內(nèi)大部分手機(jī)的桌面不是系統(tǒng)原生的<br/>
     * 更多請(qǐng)參考{@link #isShortCutExist(Context, String)}<br/>
     * 桌面有兩種,系統(tǒng)桌面(ROM自帶)與第三方桌面,一般只考慮系統(tǒng)自帶<br/>
     * 第三方桌面如果沒有實(shí)現(xiàn)系統(tǒng)響應(yīng)的方法是無(wú)法判斷的,比如GO桌面<br/>
     */
    public static boolean isShortCutExist(Context context, String title, Intent intent) {
        boolean result = false;
        try {
            ContentResolver cr = context.getContentResolver();
            Uri uri = getUriFromLauncher(context);
            Cursor c = cr.query(uri, new String[]{"title", "intent"}, "title=?  and intent=?",
                    new String[]{title, intent.toUri(0)}, null);
            if (c != null && c.getCount() > 0) {
                result = true;
            }
            if (c != null && !c.isClosed()) {
                c.close();
            }
        } catch (Exception ex) {
            result = false;
            ex.printStackTrace();
        }
        return result;
    }

    private static Uri getUriFromLauncher(Context context) {
        StringBuilder uriStr = new StringBuilder();
        String authority = LauncherUtil.getAuthorityFromPermissionDefault(context);
        if (authority == null || authority.trim().equals("")) {
            authority = LauncherUtil.getAuthorityFromPermission(context, LauncherUtil.getCurrentLauncherPackageName(context) + ".permission.READ_SETTINGS");
        }
        uriStr.append("content://");
        if (TextUtils.isEmpty(authority)) {
            int sdkInt = android.os.Build.VERSION.SDK_INT;
            if (sdkInt < 8) { // Android 2.1.x(API 7)以及以下的
                uriStr.append("com.android.launcher.settings");
            } else if (sdkInt < 19) {// Android 4.4以下
                uriStr.append("com.android.launcher2.settings");
            } else {// 4.4以及以上
                uriStr.append("com.android.launcher3.settings");
            }
        } else {
            uriStr.append(authority);
        }
        uriStr.append("/favorites?notify=true");
        return Uri.parse(uriStr.toString());
    }

這里有兩個(gè)重載的isShortCutExist方法,唯一的區(qū)別就是最后一個(gè)參數(shù)——intent,加這個(gè)參數(shù)的原因,在注釋中已經(jīng)寫了,更加精確。而getUriFromLauncher方法,是給調(diào)用的ContentResolver提供Uri。構(gòu)造的時(shí)候,可以看見,Android的版本話碎片問題,是多么的嚴(yán)重……

這樣在添加快捷方式前,通過這個(gè)判斷下,就可以只添加一個(gè)快捷方式了。

為任意PackageName的App添加快捷方式

知道了我們是如何判斷快捷方式是是否存在的,我們就可以通過這種思路來(lái)為任意PackageName的App添加快捷方式,代碼如下:

    /**
     * 為PackageName的App添加快捷方式
     *
     * @param context context
     * @param pkg     待添加快捷方式的應(yīng)用包名
     * @return 返回true為正常執(zhí)行完畢
     */
    public static boolean addShortcutByPackageName(Context context, String pkg) {
        // 快捷方式名
        String title = "unknown";
        // MainActivity完整名
        String mainAct = null;
        // 應(yīng)用圖標(biāo)標(biāo)識(shí)
        int iconIdentifier = 0;
        // 根據(jù)包名尋找MainActivity
        PackageManager pkgMag = context.getPackageManager();
        Intent queryIntent = new Intent(Intent.ACTION_MAIN, null);
        queryIntent.addCategory(Intent.CATEGORY_LAUNCHER);// 重要,添加后可以進(jìn)入直接已經(jīng)打開的頁(yè)面
        queryIntent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        queryIntent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);

        List<ResolveInfo> list = pkgMag.queryIntentActivities(queryIntent,
                PackageManager.GET_ACTIVITIES);
        for (int i = 0; i < list.size(); i++) {
            ResolveInfo info = list.get(i);
            if (info.activityInfo.packageName.equals(pkg)) {
                title = info.loadLabel(pkgMag).toString();
                mainAct = info.activityInfo.name;
                iconIdentifier = info.activityInfo.applicationInfo.icon;
                break;
            }
        }
        if (mainAct == null) {
            // 沒有啟動(dòng)類
            return false;
        }
        Intent shortcut = new Intent(
                "com.android.launcher.action.INSTALL_SHORTCUT");
        // 快捷方式的名稱
        shortcut.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
        // 不允許重復(fù)創(chuàng)建
        shortcut.putExtra("duplicate", false);
        ComponentName comp = new ComponentName(pkg, mainAct);
        shortcut.putExtra(Intent.EXTRA_SHORTCUT_INTENT,
                queryIntent.setComponent(comp));
        // 快捷方式的圖標(biāo)
        Context pkgContext = null;
        if (context.getPackageName().equals(pkg)) {
            pkgContext = context;
        } else {
            // 創(chuàng)建第三方應(yīng)用的上下文環(huán)境,為的是能夠根據(jù)該應(yīng)用的圖標(biāo)標(biāo)識(shí)符尋找到圖標(biāo)文件。
            try {
                pkgContext = context.createPackageContext(pkg,
                        Context.CONTEXT_IGNORE_SECURITY
                                | Context.CONTEXT_INCLUDE_CODE);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
        if (pkgContext != null) {
            Intent.ShortcutIconResource iconRes = Intent.ShortcutIconResource
                    .fromContext(pkgContext, iconIdentifier);
            shortcut.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconRes);
        }
        // 發(fā)送廣播,讓接收者創(chuàng)建快捷方式
        // 需權(quán)限<uses-permission
        // android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
        context.sendBroadcast(shortcut);
        return true;
    }

創(chuàng)建快捷方式之——星宿派

所謂星宿派,是指我們使用一些Trick來(lái)解決多Launcher適配的問題。

由于快捷方式的碎片化非常嚴(yán)重,所以,你顧得上這種ROM,顧不上其它ROM。例如,在原生ROM上,你需要使用類似原生的Launcher權(quán)限:

    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />

但是,在其它ROM上呢,例如華為,你需要這樣的權(quán)限:

    <uses-permission android:name="com.huawei.launcher3.permission.READ_SETTINGS" />
    <uses-permission android:name="com.huawei.launcher3.permission.WRITE_SETTINGS" />

為了程序能夠通用性夠強(qiáng),理論上我們得為所有不使用原生Launcher權(quán)限的Launcher配置權(quán)限代碼,是的,你妹聽錯(cuò),是所有,只有通過這種奇技淫巧,才能適配更多的Launcher,這里貼一部分給大家爽一下:

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

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

    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />

    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />

    <uses-permission android:name="com.android.launcher2.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.launcher2.permission.WRITE_SETTINGS" />

    <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />

    <uses-permission android:name="org.adw.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="org.adw.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.htc.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.qihoo360.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.qihoo360.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.lge.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.lge.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="net.qihoo.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="net.qihoo.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="org.adwfreak.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="org.adwfreak.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="org.adw.launcher_donut.permission.READ_SETTINGS" />
    <uses-permission android:name="org.adw.launcher_donut.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.huawei.launcher3.permission.READ_SETTINGS" />
    <uses-permission android:name="com.huawei.launcher3.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.fede.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.fede.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.sec.android.app.twlauncher.settings.READ_SETTINGS" />
    <uses-permission android:name="com.sec.android.app.twlauncher.settings.WRITE_SETTINGS" />
    <uses-permission android:name="com.anddoes.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.anddoes.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.tencent.qqlauncher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.tencent.qqlauncher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.huawei.launcher2.permission.READ_SETTINGS" />
    <uses-permission android:name="com.huawei.launcher2.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.android.mylauncher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.mylauncher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.ebproductions.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.ebproductions.android.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.oppo.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.oppo.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.miui.mihome2.permission.READ_SETTINGS" />
    <uses-permission android:name="com.miui.mihome2.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.huawei.android.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="telecom.mdesk.permission.READ_SETTINGS" />
    <uses-permission android:name="telecom.mdesk.permission.WRITE_SETTINGS" />
    <uses-permission android:name="dianxin.permission.ACCESS_LAUNCHER_DATA" />

這時(shí)候大家肯定要問了,你申請(qǐng)這么多權(quán)限,用戶在安裝App的時(shí)候,不是要崩潰了,尼瑪,這么多看都看不過來(lái)啊,其實(shí),根本不需要擔(dān)心,因?yàn)檫@些基本都是各自ROM中的第三方ROM權(quán)限,在用戶安裝的時(shí)候,他們通常會(huì)被解析成原生Launcher的權(quán)限,例如:添加、修改桌面快捷方式。并不會(huì)將所有的權(quán)限都寫出來(lái)。

創(chuàng)建快捷方式之——西域派

所謂西域派,是因?yàn)槲蚁氩怀銎渌至恕N饔蛞慌?,使用其他方式?lái)實(shí)現(xiàn)類似快捷方式的方法。

快捷方式的確是我們?yōu)閼?yīng)用導(dǎo)流的一個(gè)非常重要的入口,但是,由于碎片化實(shí)在太嚴(yán)重,所以,我們可以使用在Launcher App列表中為應(yīng)用增加一個(gè)入口的方式來(lái)為App導(dǎo)流,簡(jiǎn)單的說(shuō),就是增進(jìn)一個(gè)App的入口Activity。

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity
    android:name="com.hujiang.hj_shortcut_lib.HJShortcutActivity"
    android:theme="@style/Base.Theme.AppCompat.Dialog">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

非常簡(jiǎn)單,相信大家都知道這種方式來(lái)給App增加一個(gè)Activity入口。但是,這種方式,我們?nèi)绾文軌蜃杂傻目刂七@個(gè)入口是否顯示呢?

奇技PackageManager

PackageManager提供了一系列Package的管理方法,當(dāng)然,也包含了我們非常關(guān)心的啟用、停用組件這一方法,這個(gè)方法在Root情況下,可以修改任一App的任意組件,在普通情況下,對(duì)自身App有絕對(duì)權(quán)限。使用方法也非常簡(jiǎn)單:

    public static void toggleFlowEntrance(Context context, Class launcherClass) {
        PackageManager packageManager = context.getPackageManager();
        ComponentName componentName = new ComponentName(context, launcherClass);
        int res = packageManager.getComponentEnabledSetting(componentName);
        if (res == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT ||
                res == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
            // 隱藏應(yīng)用圖標(biāo)
            packageManager.setComponentEnabledSetting(
                    componentName,
                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                    PackageManager.DONT_KILL_APP);
        } else {
            // 顯示應(yīng)用圖標(biāo)
            packageManager.setComponentEnabledSetting(
                    componentName,
                    PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
                    PackageManager.DONT_KILL_APP);
        }
    }

一統(tǒng)江湖

前面我們分析了各種快捷方式、Launcher入口的方式來(lái)對(duì)App進(jìn)行導(dǎo)流,當(dāng)然,這不是我們的目的,我們的目的是能夠掌握Android快捷方式的哭花寶典而不用那個(gè)啥。

所以,下面我封裝了一個(gè)shortcut的開源庫(kù),從而可以盡可能的忽略ROM的差異,來(lái)使用快捷方式和Launcher入口。

項(xiàng)目地址:

https://github.com/xuyisheng/ShortcutHelper

目前該項(xiàng)目還在測(cè)試階段,還要很多問題和適配bug需要解決,歡迎大家提issue。

README如下:

ShortcutLib使用指南

本項(xiàng)目目前還在測(cè)試階段,請(qǐng)大家多提issue,共同完善。

項(xiàng)目意義

快速使用shortcut,避免各種ROM適配導(dǎo)致的各種問題。

項(xiàng)目可用功能API

  • 增加快捷方式
    /**
     * 添加快捷方式
     *
     * @param context      context
     * @param actionIntent 要啟動(dòng)的Intent
     * @param name         name
     * @param allowRepeat  是否允許重復(fù)
     * @param iconBitmap   快捷方式圖標(biāo)
     */
    public static void addShortcut(Context context, Intent actionIntent, String name,
                                   boolean allowRepeat, Bitmap iconBitmap)
  • 判斷快捷方式是否存在

基礎(chǔ)方式

    /**
     * 判斷快捷方式是否存在
     * <p/>
     * 檢查快捷方式是否存在 <br/>
     * <font color=red>注意:</font> 有些手機(jī)無(wú)法判斷是否已經(jīng)創(chuàng)建過快捷方式<br/>
     * 因此,在創(chuàng)建快捷方式時(shí),請(qǐng)?zhí)砑?lt;br/>
     * shortcutIntent.putExtra("duplicate", false);// 不允許重復(fù)創(chuàng)建<br/>
     * 最好使用{@link #isShortCutExist(Context, String, Intent)}
     * 進(jìn)行判斷,因?yàn)榭赡苡行?yīng)用生成的快捷方式名稱是一樣的的<br/>
     *
     * @param context context
     * @param title   快捷方式名
     * @return 是否存在
     */
    public static boolean isShortCutExist(Context context, String title)

嚴(yán)格方式(增加Intent的檢查)

    /**
     * 判斷快捷方式是否存在
     * <p/>
     * 不一定所有的手機(jī)都有效,因?yàn)閲?guó)內(nèi)大部分手機(jī)的桌面不是系統(tǒng)原生的<br/>
     * 更多請(qǐng)參考{@link #isShortCutExist(Context, String)}<br/>
     * 桌面有兩種,系統(tǒng)桌面(ROM自帶)與第三方桌面,一般只考慮系統(tǒng)自帶<br/>
     * 第三方桌面如果沒有實(shí)現(xiàn)系統(tǒng)響應(yīng)的方法是無(wú)法判斷的,比如GO桌面<br/>
     *
     * @param context context
     * @param title   快捷方式名
     * @param intent  快捷方式Intent
     * @return 是否存在
     */
    public static boolean isShortCutExist(Context context, String title, Intent intent)

更新快捷方式

    /**
     * 更新桌面快捷方式圖標(biāo),不一定所有圖標(biāo)都有效(有可能需要系統(tǒng)權(quán)限)
     *
     * @param context context
     * @param title   快捷方式名
     * @param intent  快捷方式Intent
     * @param bitmap  快捷方式Icon
     */
    public static void updateShortcutIcon(Context context, String title, Intent intent, Bitmap bitmap)

需要注意的是,更新快捷方式在很多手機(jī)上都不能生效,需要系統(tǒng)權(quán)限。可以通過先刪除、再新增的方式來(lái)實(shí)現(xiàn)。

為任意PackageName的App添加快捷方式

    /**
     * 為任意PackageName的App添加快捷方式
     *
     * @param context context
     * @param pkg     待添加快捷方式的應(yīng)用包名
     * @return 返回true為正常執(zhí)行完畢
     */
    public static boolean addShortcutByPackageName(Context context, String pkg)

移除快捷方式

    /**
     * 移除快捷方式
     *
     * @param context      context
     * @param actionIntent 要啟動(dòng)的Intent
     * @param name         name
     */
    public static void removeShortcut(Context context, Intent actionIntent, String name)

顯示隱藏Launcher入口

    /**
     * 顯示\隱藏Launcher入口
     *
     * @param context       context
     * @param launcherClass launcherClass
     */
    public static void toggleFlowEntrance(Context context, Class launcherClass)

使用Launcher入口需要在AndroidMainifest文件中注冊(cè)新增的入口Activity,例如:

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity
    android:name="com.xxx.xxxxx"
    android:theme="@style/Base.Theme.AppCompat.Dialog">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

使用示例

    public void addShortcutTest(View view) {
        // 系統(tǒng)方式創(chuàng)建
        // ShortcutUtils.addShortcut(this, getShortCutIntent(), mShortcutName);

        // 創(chuàng)建前判斷是否存在
        if (!ShortcutSuperUtils.isShortCutExist(this, mShortcutName, getShortCutIntent())) {
            ShortcutUtils.addShortcut(this, getShortCutIntent(), mShortcutName, false,
                    BitmapFactory.decodeResource(getResources(), com.hujiang.hj_shortcut_lib.R.drawable.ocsplayer));
            finish();
        } else {
            Toast.makeText(this, "Shortcut is exist!", Toast.LENGTH_SHORT).show();
        }

        // 為某個(gè)包創(chuàng)建快捷方式
        // ShortcutSuperUtils.addShortcutByPackageName(this, this.getPackageName());
    }

    public void removeShortcutTest(View view) {
        ShortcutUtils.removeShortcut(this, getShortCutIntent(), mShortcutName);
    }

    public void updateShortcutTest(View view) {
        ShortcutSuperUtils.updateShortcutIcon(this, mShortcutName, getShortCutIntent(),
                BitmapFactory.decodeResource(getResources(), com.hujiang.hj_shortcut_lib.R.mipmap.ic_launcher));
    }

    public void toggleFlowEntrance(View view) {
        FlowEntranceUtil.toggleFlowEntrance(this, HJShortcutActivity.class);
    }

    private Intent getShortCutIntent() {
        // 使用MAIN,可以避免部分手機(jī)(比如華為、HTC部分機(jī)型)刪除應(yīng)用時(shí)無(wú)法刪除快捷方式的問題
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.setClass(MainActivity.this, HJShortcutActivity.class);
        return intent;
    }
最后編輯于
?著作權(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)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,765評(píng)論 25 709
  • 注:本文完全拷貝自https://developer.android.com/guide/components/i...
    RxCode閱讀 1,951評(píng)論 1 13
  • 親愛的K先生: 我記得你有一次說(shuō)過我文藝,為了對(duì)得起這個(gè)形容詞,我決定用一種相對(duì)文藝方式來(lái)思忖這段感情——寫一封分...
    目分目分目分閱讀 1,118評(píng)論 12 20
  • 2017.03.15 本篇承接394.朝花夕拾61~滑冰什剎海,繼續(xù)回憶一下滑冰的歷程。 冬天,在什剎海冰場(chǎng)上滑冰...
    摹喵居士閱讀 242評(píng)論 0 0
  • 1、在“學(xué)習(xí)區(qū)”選擇學(xué)習(xí)的高度 心理學(xué)家把人的技能練習(xí)分為三個(gè)區(qū)域:第一個(gè)區(qū)域是“舒適區(qū)”,是我們已經(jīng)熟練掌握的各...
    sophia夏閱讀 418評(píng)論 0 1

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