Android 適配多種ROM的快捷方式

希爾瓦娜斯女神發表於2015-12-02

快捷方式 應該來說 很多人都做過,我們就來看一下基本的快捷方式 是怎麼實現的,會有什麼問題?

首先 肯定要獲取許可權:

1  <!-- 新增快捷方式 -->
2     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
3     <!-- 移除快捷方式 -->
4     <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
5     <!-- 查詢快捷方式 -->
6     <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />

然後定義一下我們要發起的action:

1  //刪除快捷方式的action
2  public static final String ACTION_REMOVE_SHORTCUT = "com.android.launcher.action.UNINSTALL_SHORTCUT";
3  //新增快捷方式的action
4  public static final String ACTION_ADD_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT";

然後寫2個方法即可:

 1  //刪除快捷方式
 2   public static void removeShortcut(Context context, Intent actionIntent, String name) {
 3         Intent intent = new Intent(ACTION_REMOVE_SHORTCUT);
 4         intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
 5         intent.putExtra("duplicate", false);
 6         intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);
 7         context.sendBroadcast(intent);
 8  }
 9 //增加快捷方式  
10 public static void addShortcut(Context context, Intent actionIntent, String name,
11                                    boolean allowRepeat, Bitmap iconBitmap) {
12         Intent addShortcutIntent = new Intent(ACTION_ADD_SHORTCUT);
13         // 是否允許重複建立
14         addShortcutIntent.putExtra("duplicate", allowRepeat);
15         // 快捷方式的標題
16         addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
17         // 快捷方式的圖示
18         addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, iconBitmap);
19         // 快捷方式的動作
20         addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);
21         context.sendBroadcast(addShortcutIntent);
22 }

這種方法,大部分的手機都能正常使用。但是在某些國產手機上會有各種各樣的問題。比如hw的手機這樣做就完全無效。

小米的手機 無法重複建立快捷方式等。那現在看看 有沒有什麼方法 能解決這些問題。

首先我們來看一張圖:

這張圖很清晰的告訴我們launcher這個應用下面 是有一個資料庫的。

我們可以開啟這個資料庫 看看到底是什麼?

 

你看這個就一目瞭然了,快捷方式 都是存在於這個表裡面的!所以 我們除了傳送廣播 可以建立快捷方式以外,我們直接運算元據庫也應該是可以建立快捷方式的。

但是我們要注意啊,各家的lanucher 都有很大不同的,我上面的截圖 是用的模擬器,所以是官方的rom,那路徑肯定就是常規的,但是深度定製的android系統

大家都知道各家lanucher都是自己在做,所以favorites 這張表的位置到底在哪裡,這就是個問題了。我們需要先查詢出來這張表到底在哪個位置才能好操作這個表,

要想知道這個表在哪個位置,我們首先要知道 對於這個rom來說,是哪個lanucher在啟作用?包名是什麼?

 1 //此函式返回當前rom下的lanucher的包名
 2     private String getCurrentLanucherPackageName(Context context)
 3     {
 4         //這個intent很好理解 就是啟動lanucher的intent
 5         Intent intent=new Intent(Intent.ACTION_MAIN);
 6         intent.addCategory(Intent.CATEGORY_HOME);
 7         //getPackageManager().resolveActivity 這個函式就是查詢是否有符合條件的activity的
 8         ResolveInfo res=context.getPackageManager().resolveActivity(intent,0);
 9         //為避免空指標 我們要判定下空,雖然你我都知道這種情況不會發生
10         if(res==null||res.activityInfo==null)
11         {
12             return "";
13         }
14         return res.activityInfo.packageName;
15     }

有些人可能對於4-5行還是理解不了,為什麼這個相當於是啟動lanucher的intent 其實很簡單,我們在android studio裡 run一個app的時候,我們通常都能看到下面這個介面:

 

你看android studio 實際上安裝完我們的應用以後 也是通過 這個intent來啟動手機裡的lanucher 然後讓lanucher來執行我們的app,因為studio也不知道你手機裡的lanucher到底是哪個

所以只能用intent來完成,這也就是上述程式碼能必定成功執行的原因!否則的話 android studio 就無法把你的app run進去了~~

 

當然了你也可以進入shell ,打ps 命令看看到底是不是有這個 包名的 程式在 執行中~~

 

好 拿到了我們的lanucher的包名,下面一步就是去我們的包名下 操作那個資料庫即可了。那顯然這個步驟 最合適的就是contentprovider來操作了。

 

 1 //此函式返回 要查詢的permission的 provider的 authority
 2     private String getAuthorityFromPermission(Context context, String permission) {
 3         //返回安裝的app的 provider的資訊
 4         List<PackageInfo> packs = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
 5         //遍歷獲取到的安裝包的資訊
 6         for (PackageInfo pack : packs) {
 7             //每個安裝包提供的provider 都在這個陣列裡面
 8             ProviderInfo[] providers = pack.providers;
 9             if (providers != null) {
10                 //遍歷每個provider 看需要的許可權是否與我們傳進來的許可權引數相等
11                 for (ProviderInfo providerInfo : providers) {
12                     if (permission.equals(providerInfo.readPermission) || permission.equals(providerInfo.writePermission)) {
13                         return providerInfo.authority;
14                     }
15                 }
16             }
17         }
18         return "";
19     }
1   private String getAuthorityFromPermissionDefault(Context context) {
2         return getAuthorityFromPermission(context, "com.android.launcher.permission.READ_SETTINGS");
3     }
 1  private  Uri getUriFromLauncher(Context context) {
 2         StringBuilder uriStrBuilder = new StringBuilder();
 3         //為了速度考慮,這裡我們先查詢預設的 看是否能查詢到 因為多數手機的rom還是用的預設的lanucher
 4         String authority = getAuthorityFromPermissionDefault(context);
 5         //如果找不到的話 就說明這個rom一定是用的其他的自定義的lanucher。那就拼一下 這個自定義的lanucher的permission再去查詢一次
 6         if (authority == null || authority.trim().equals("")) {
 7             authority = getAuthorityFromPermission(context,getCurrentLanucherPackageName(context) + ".permission.READ_SETTINGS");
 8         }
 9         uriStrBuilder.append("content://");
10         //如果連上面的方法都查詢不到這個authority的話 那下面的方法 就肯定查詢到了 但是很少有情況會是如下這種
11         //多數都是else裡面的邏輯
12         if (TextUtils.isEmpty(authority)) {
13             int sdkInt = android.os.Build.VERSION.SDK_INT;
14             if (sdkInt < 8) { // Android 2.1.x(API 7)以及以下的
15                 uriStrBuilder.append("com.android.launcher.settings");
16             } else if (sdkInt < 19) {// Android 4.4以下
17                 uriStrBuilder.append("com.android.launcher2.settings");
18             } else {// 4.4以及以上
19                 uriStrBuilder.append("com.android.launcher3.settings");
20             }
21         } else {
22             uriStrBuilder.append(authority);
23         }
24         uriStrBuilder.append("/favorites?notify=true");
25         return Uri.parse(uriStrBuilder.toString());
26     }

好,到這裡 我們就能拿到所有rom 任意一款手機的 快捷方式 那張資料庫表對應的uri了。

那到這裡應該來說問題就基本解決了,你所有對快捷方式的操作 都可以直接通過這個uri來進行,無非就是一些crud的拼裝。

再也不需要經過廣播 那一道程式了,但是這裡要注意的是 這種方法通常耗時都比較久,根據手機的效能的不同 200ms-600ms 才能完成uri的查詢。所以記得做一下非同步處理。

 

並且所有你對lanucher的 需求 都可以這麼來做,比方說有些功能 在使用原生lanucher的手機上使用正常,在小米 華為 oppo使用不正常了,你就去找出來那個不正常的rom

的lanucher的 包名,然後找出他provider需要的許可權,然後在你的manifest裡 直接加許可權 應該就可以正常使用了。第三方lanucher 引起的bug 基本上都可以通過這個方案

來解決。

 

相關文章