Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android launcher3桌面快捷方式分析

android launcher3桌面快捷方式分析

編輯:關於Android編程

背景

一般情況下,為了讓用戶更方便的打開應用,程序會在桌面上生成一些快捷方式。
本來呢,如果是原生的桌面,其實是十分簡單,直接調用系統相關的API就行了。但是眾多的系統廠商以及眾多第三方自己定制的桌面(Launcher),導致在適配、兼容方面存在很多問題。
比如,有些桌面無法刪除快捷方式(比如小米),有些桌面無法生成快捷方式(比如錘子),有些系統無法更新桌面圖標(比如華為榮耀6)。
在升級、降級的時候快捷方式發生變化;比如,全部變成應用的主圖標,升級、降級後點擊快捷方式沒有反應,刪除應用後無法刪除快捷方式。
很多問題都是需要解決的,雖然有些由於系統限制,沒有辦法搞定所有的,但是仍然需要尋求一個最優的方案。這也就是本文需要討論的問題。
本文說指的快捷方式是指應用桌面快捷方式,不包含長按彈出的生成快捷方式。
快捷方式所有信息都是存在於launcher的favorite表。一般需要用到的字段為_id,title,intent,iconResource,icon,分別表示 快捷方式名稱,快捷方式intent,快捷方式圖標(本地),快捷方式圖標(data二進制壓縮數據)。

 

兩個intent數據如下

數據可以通過SQLite Editor查看,需要已經ROOT的手機

實現

增加快捷方式

在AndroidManifest.xml增加權限

同時,根據Intent是隱式還是顯示在相關的Activity聲明相關的intent-filter。
相關代碼:

刪除快捷方式

跟增加快捷方式一樣,也是需要增加權限的。加上

相關代碼:

快捷方式修改

需要增加權限

如果適配所有桌面,請添加附錄中第二條所列出的權限。
系統並沒有提供API去更改桌面快捷方式。只能通過其他猥瑣的辦法了,可行的的辦法之一就是通過ContentProvider去更改數據庫相關的信息。當然有人會說了,先刪掉快捷方式,再重新創建不就行了?這是個辦法。但是有些系統是無法刪除快捷方式的;另外,刪除快捷方式與創建快捷方式都是通過廣播實現的,這個地方需要控制兩者的時間間隔。權衡之後,選用第一種辦法相對穩妥。
廢話不多少,上代碼。
/**
*更新桌面快捷方式圖標,不一定所有圖標都有效
*如果快捷方式不存在,則不更新
.
*/
publicstaticvoidupdateShortcutIcon(Contextcontext,Stringtitle,Intentintent,Bitmapbitmap){
if(bitmap==null){
XLog.i(TAG,"updateshortcuticon,bitmapempty");
return;
}
try{
finalContentResolvercr=context.getContentResolver();
StringBuilderuriStr=newStringBuilder();
StringurlTemp="";
Stringauthority=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)){
intsdkInt=android.os.Build.VERSION.SDK_INT;
if(sdkInt<8){//Android2.1.x(API7)以及以下的
uriStr.append("com.android.launcher.settings");
}elseif(sdkInt<19){//Android4.4以下
uriStr.append("com.android.launcher2.settings");
}else{//4.4以及以上
uriStr.append("com.android.launcher3.settings");
}
}else{
uriStr.append(authority);
}
urlTemp=uriStr.toString();
uriStr.append("/favorites?notify=true");
Uriuri=Uri.parse(uriStr.toString());
Cursorc=cr.query(uri,newString[]{"_id","title","intent"},
"title=?andintent=?",
newString[]{title,intent.toUri(0)},null);
intindex=-1;
if(c!=null&&c.getCount()>0){
c.moveToFirst();
index=c.getInt(0);//獲得圖標索引
ContentValuescv=newContentValues();
cv.put("icon",flattenBitmap(bitmap));
Uriuri2=Uri.parse(urlTemp+"/favorites/"+index+"?notify=true");
inti=context.getContentResolver().update(uri2,cv,null,null);
context.getContentResolver().notifyChange(uri,null);//此處不能用uri2,是個坑
XLog.i(TAG,"updateok:affected"+i+"rows,indexis"+index);
}else{
XLog.i(TAG,"updateresultfailed");
}
if(c!=null&&!c.isClosed()){
c.close();
}
}catch(Exceptionex){
ex.printStackTrace();
XLog.i(TAG,"updateshortcuticon,geterrors:"+ex.getMessage());
}
}
privatestaticbyte[]flattenBitmap(Bitmapbitmap){
//Trygoguesstimatehowmuchspacetheiconwilltakewhenserialized
//toavoidunnecessaryallocations/copiesduringthewrite.
intsize=bitmap.getWidth()*bitmap.getHeight()*4;
ByteArrayOutputStreamout=newByteArrayOutputStream(size);
try{
bitmap.compress(Bitmap.CompressFormat.PNG,100,out);
out.flush();
out.close();
returnout.toByteArray();
}catch(IOExceptione){
XLog.w(TAG,"Couldnotwriteicon");
returnnull;
}
}

 

快捷方式存在判斷

 

需要增加的權限同修改快捷方式
雖然說通過SharePreference來保證快捷方式不會重復創建,以及通過shortcutIntent.putExtra(“duplicate”, false)也可以確保,但是為了萬無一失,還是可以通過去查詢數據判斷快捷方式是否存在,來避免重復創建。 代碼如下:

/**
*檢查快捷方式是否存在
*注意:有些手機無法判斷是否已經創建過快捷方式
*因此,在創建快捷方式時,請添加
*shortcutIntent.putExtra("duplicate",false);//不允許重復創建
*最好使用{@link#isShortCutExist(Context,String,Intent)}
*進行判斷,因為可能有些應用生成的快捷方式名稱是一樣的的
*此處需要在AndroidManifest.xml中配置相關的桌面權限信息
*錯誤信息已捕獲
*/
publicstaticbooleanisShortCutExist(Contextcontext,Stringtitle){
booleanresult=false;
try{
finalContentResolvercr=context.getContentResolver();
StringBuilderuriStr=newStringBuilder();
Stringauthority=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)){
intsdkInt=android.os.Build.VERSION.SDK_INT;
if(sdkInt<8){//Android2.1.x(API7)以及以下的
uriStr.append("com.android.launcher.settings");
}elseif(sdkInt<19){//Android4.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");
Uriuri=Uri.parse(uriStr.toString());
Cursorc=cr.query(uri,newString[]{"title"},
"title=?",
newString[]{title},null);
if(c!=null&&c.getCount()>0){
result=true;
}
if(c!=null&&!c.isClosed()){
c.close();
}
}catch(Exceptione){
e.printStackTrace();
result=false;
}
returnresult;
}
/**
*不一定所有的手機都有效,因為國內大部分手機的桌面不是系統原生的
*更多請參考{@link#isShortCutExist(Context,String)}
*桌面有兩種,系統桌面(ROM自帶)與第三方桌面,一般只考慮系統自帶
*第三方桌面如果沒有實現系統響應的方法是無法判斷的,比如GO桌面
*此處需要在AndroidManifest.xml中配置相關的桌面權限信息
*錯誤信息已捕獲
*/
publicstaticbooleanisShortCutExist(Contextcontext,Stringtitle,Intentintent){
booleanresult=false;
try{
finalContentResolvercr=context.getContentResolver();
StringBuilderuriStr=newStringBuilder();
Stringauthority=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)){
intsdkInt=android.os.Build.VERSION.SDK_INT;
if(sdkInt<8){//Android2.1.x(API7)以及以下的
uriStr.append("com.android.launcher.settings");
}elseif(sdkInt<19){//Android4.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");
Uriuri=Uri.parse(uriStr.toString());
Cursorc=cr.query(uri,newString[]{"title","intent"},
"title=?andintent=?",
newString[]{title,intent.toUri(0)},null);
if(c!=null&&c.getCount()>0){
result=true;
}
if(c!=null&&!c.isClosed()){
c.close();
}
}catch(Exceptionex){
result=false;
ex.printStackTrace();
}
returnresult;
}

 

兼容與注意事項

兼容

所有的快捷方式Intent如果不是之前版本的存在很大問題,絕對不要改變參數,否則升級或者降級時快捷方式會出現問題;
同時,盡可能的采用隱式調用,自定義CATEGORY,而不是自定義ACTION,ACTION參數一定要為ACTION_MAIN,否則有些手機在卸載時無法刪除快捷方式(WTF)。

注意事項

  • 【所有】activity路徑的變更導致老版本升級之後快捷方式無法使用
    —> 1.一旦使用確定了activity的包路徑,之後就不要再變更;
    —> 2.盡可能使用隱式調用,但是如果之前已經發出去的版本,為了兼容性,就必須一直使用老的方式,新版本的盡可能的不要更改方式,如果用戶降級,老版本快捷方式會無法使用。
  • 【部分】多個快捷方式指向一個activity導致部分手機(三星SII)升級時圖標變成應用圖標
    —> 盡可能的避免多個快捷方式指向同一個activity,可能通過多個activity再跳轉過去
  • 【部分】應用刪除時無法刪除快捷方式。與系統桌面Launcher實現有關。
    —> 為了適配所有Launcher,Intent Action使用Intent.ACTION_MAIN。如果是隱式調用,盡可能自定義CATEGORY,而不是自定義ACTION。
  • 【部分】應用升級時需要刪除老版本部分快捷方式,但是部分手機無法刪除
    —> 無解
  • 【部分】第三方桌面無法生成、刪除、更新快捷方式
    —> 呵呵,一般來說生成沒有問題,但是刪除,更新大部分桌面會有問題。盡可能避免這些操作。或者專門適配該桌面,成本較高。
  • 【部分】部分桌面無法實時更新圖標,需要重啟
  • —> 無解,嘗試過重啟Launcher,但是結果是之前的快捷方式也消失了。只有重啟手機,按理來說應該是有方式觸發Launcher進行刷新的。
以上【所有】【部分】,分別表示必定出現,部分出現。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved