自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

鴻蒙動態(tài)權(quán)限申請完整規(guī)范流程和操作詳解

系統(tǒng)
文章由鴻蒙社區(qū)產(chǎn)出,想要了解更多內(nèi)容請前往:51CTO和華為官方戰(zhàn)略合作共建的鴻蒙技術(shù)社區(qū)https://harmonyos.51cto.com

 [[404224]]

想了解更多內(nèi)容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

好久沒有寫博客了,正好今天HarmonyOS發(fā)布會,看完激動人心的發(fā)布會之后,還是覺得需要寫些東西。本來準(zhǔn)備分享之前自己做的分布式流轉(zhuǎn)的視頻播放器的,但是分布式流轉(zhuǎn)開發(fā)內(nèi)容已經(jīng)有好多博主發(fā)表過了,于是搜了下社區(qū)內(nèi)容,發(fā)現(xiàn)動態(tài)權(quán)限申請這塊的內(nèi)容沒人發(fā)布,并且發(fā)現(xiàn)有幾篇博客的動態(tài)權(quán)限申請的代碼過于簡單存在漏洞。于是想著把這塊內(nèi)容整理整理發(fā)出來。

一、權(quán)限概述

已在config.json文件中聲明的非敏感權(quán)限,非敏感權(quán)限不涉及用戶的敏感數(shù)據(jù)或危險操作,會在應(yīng)用安裝時自動授予,該類權(quán)限的授權(quán)方式為系統(tǒng)授權(quán)(system_grant)。

敏感權(quán)限需要應(yīng)用動態(tài)申請,通過運(yùn)行時發(fā)送彈窗的方式請求用戶授權(quán),該類權(quán)限的授權(quán)方式為用戶授權(quán)(user_grant)。

非敏感權(quán)限代碼編寫比較簡單,這里就不做講解。本文只講解敏感權(quán)限如何編寫代碼,即動態(tài)權(quán)限申請流程。

二、敏感權(quán)限列表

敏感權(quán)限的申請需要按照動態(tài)申請流程向用戶申請授權(quán)。

三、采用一個簡單的相冊案例演示動態(tài)權(quán)限申請開發(fā)流程

相冊需要讀取本機(jī)存儲的權(quán)限,即ohos.permission.READ_USER_STORAGE,它屬于敏感權(quán)限。

1、項目效果圖以及操作場景展示

(1)首次安裝app,用戶需要讀取相冊數(shù)據(jù)時,會彈出對話框提醒用戶授權(quán)。

點(diǎn)擊"允許"之后才能正常加載數(shù)據(jù)。

(2)如果點(diǎn)擊禁止,并且沒有勾選"禁止授權(quán)并且禁止后續(xù)再彈框提示",那么下次打開app時依然會進(jìn)行彈框提示。

(3)如果點(diǎn)擊禁止,并且勾選了"禁止授權(quán)并且禁止后續(xù)再彈框提示",那么后續(xù)也不會再繼續(xù)彈框進(jìn)行授權(quán)了,也就看不到數(shù)據(jù)。如果需要進(jìn)行授權(quán)的話,需要用戶自行去系統(tǒng)設(shè)置中手動更改權(quán)限。此時我們應(yīng)該在頁面上友好地使用toast提醒用戶去系統(tǒng)設(shè)置中手動更改權(quán)限。

請記住我現(xiàn)在描述的3種操作場景,與后續(xù)編寫代碼緊密相關(guān),有些開發(fā)者編寫代碼一行代碼就搞定了動態(tài)授權(quán)操作,那樣的代碼只能滿足我說的第一種使用場景,后面兩種無法滿足,使用起來非常不友好。

2、代碼編寫步驟

(1)配置config.json

首先在config.json的module中添加如下配置:

  1. "reqPermissions": [ 
  2.      { 
  3.        "name""ohos.permission.READ_USER_STORAGE"
  4.        "reason""$string:permreason_storage"
  5.        "usedScene"
  6.        { 
  7.          "ability": ["com.xdw.album.MainAbility"], 
  8.          "when""always" 
  9.        } 
  10.      } 
  11.    ] 

 權(quán)限申請格式采用數(shù)組格式,可支持同時申請多個權(quán)限,權(quán)限個數(shù)最多不能超過1024個。

reqPermissions權(quán)限申請字段說明如下表

(2)編寫權(quán)限彈框觸發(fā)代碼

此步驟需要結(jié)合自己項目實際業(yè)務(wù)邏輯編寫,本相冊項目是在主頁面打開的時候就觸發(fā)了權(quán)限的申請,因此修改MainAbilitySlice代碼,在onStart的時候就去進(jìn)行校驗,具體代碼如下

  1. if (verifySelfPermission("ohos.permission.READ_USER_STORAGE") != IBundleManager.PERMISSION_GRANTED) { 
  2.             // 應(yīng)用未被授予權(quán)限 
  3.             if (canRequestPermission("ohos.permission.READ_USER_STORAGE")) { 
  4.                 // 是否可以申請彈框授權(quán)(首次申請或者用戶未選擇禁止且不再提示) 
  5.                 requestPermissionsFromUser( 
  6.                         new String[] { "ohos.permission.READ_USER_STORAGE" } , MY_PERMISSIONS_REQUEST_READ_USER_STORAGE); 
  7.             } else { 
  8.                 // 顯示應(yīng)用需要權(quán)限的理由,提示用戶進(jìn)入設(shè)置授權(quán) 
  9.                 new ToastDialog(getContext()).setText("請進(jìn)入系統(tǒng)設(shè)置進(jìn)行授權(quán)").show(); 
  10.             } 
  11.         } else { 
  12.             // 權(quán)限已被授予 
  13.             //加載顯示系統(tǒng)相冊中的照片 
  14.             showPhotos(); 
  15.         } 

 這斷代碼還使用到了一個自定義的常量MY_PERMISSIONS_REQUEST_READ_USER_STORAGE,需要提前定義它,代碼如下:

  1. public static final int MY_PERMISSIONS_REQUEST_READ_USER_STORAGE = 0;   //自定義的一個權(quán)限請求識別碼,用于處理權(quán)限回調(diào) 

 第一行首先調(diào)用系統(tǒng)方法verifySelfPermission校驗權(quán)限是否已被授予,如果未授予則調(diào)用系統(tǒng)方法canRequestPermission查詢該權(quán)限是否可以申請彈框授權(quán),因為如果用戶之前如果勾選了禁止授權(quán)并且禁止后續(xù)再彈框提示,那么就不能再進(jìn)行彈框授權(quán)了,此時需要toast提示引導(dǎo)用戶自行去系統(tǒng)設(shè)置中手動更改權(quán)限。如果可以申請彈框授權(quán),則調(diào)用系統(tǒng)方法requestPermissionsFromUser進(jìn)行彈框授權(quán)(應(yīng)用上的彈框就是來自這個方法)。如果之前應(yīng)用已經(jīng)被授權(quán)過,則直接調(diào)用業(yè)務(wù)處理方法,這里自定義的業(yè)務(wù)處理方法是showPhotos,它的代碼請見后面完整MainAbilitySlice代碼。

此時還缺少一個在授權(quán)彈框上點(diǎn)擊允許授權(quán)按鈕之后的回調(diào)業(yè)務(wù)邏輯處理,該回調(diào)業(yè)務(wù)邏輯需要重寫onRequestPermissionsFromUserResult方法,而該方法是Ability類的方法,而不是AbilitySlice類的方法。因此需要在MainAbility中重寫該方法,然后在該重寫方法中調(diào)用MainAbilitySlice對象中的showPhotos方法,這個就涉及到了MainAbility與MainAbilitySlice的通信。

關(guān)于MainAbility與MainAbilitySlice的通信的具體講解請看我另外一篇博文,這里不在做詳解。

(3)編寫requestPermissionsFromUser的回調(diào)

該回調(diào)只能在Ability種進(jìn)行編寫,因此修改MainAbility的代碼,核心代碼如下:

  1. @Override 
  2.    public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) { 
  3.        super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults); 
  4.        switch (requestCode) { 
  5.            case MY_PERMISSIONS_REQUEST_READ_USER_STORAGE: { 
  6.                // 匹配requestPermissions的requestCode 
  7.                if (grantResults.length > 0 
  8.                        && grantResults[0] == IBundleManager.PERMISSION_GRANTED) { 
  9.                    // 權(quán)限被授予之后做相應(yīng)業(yè)務(wù)邏輯的處理 
  10.                    mainAbilitySlice.showPhotos(); 
  11.                } else { 
  12.                    // 權(quán)限被拒絕 
  13.                    new ToastDialog(getContext()).setText("權(quán)限被拒絕").show(); 
  14.                } 
  15.                return
  16.            } 
  17.        } 
  18.    } 

 這里對requestCode進(jìn)行了判斷,它就是我們之前自定義的權(quán)限申請碼,用來區(qū)分我們在多個地方進(jìn)行權(quán)限申請的操作,能區(qū)分每次不同請求的回調(diào)。

四、常見操作誤區(qū)

(1)只用一行簡單代碼進(jìn)行動態(tài)權(quán)限申請,而沒有提前校驗權(quán)限和回調(diào)的過程

  1. requestPermissionsFromUser( 
  2.                         new String[] { "ohos.permission.READ_USER_STORAGE" } , MY_PERMISSIONS_REQUEST_READ_USER_STORAGE); 

 這種情況就會出現(xiàn)萬一有一次禁止了權(quán)限,后面就不會顯示相冊數(shù)據(jù)并且沒人任何提示,影響用戶體驗。

(2)canRequestPermission代碼邏輯沒有編寫

該邏輯代碼不編寫,就會出現(xiàn)用戶點(diǎn)擊了"禁止授權(quán)并且禁止后續(xù)再彈框提示",然后進(jìn)入頁面就不會顯示相冊數(shù)據(jù)并且沒人任何提示,影響用戶體驗。

因此,為了加強(qiáng)用戶體驗,請不要省略上述動態(tài)權(quán)限申請的代碼編寫流程。

五、完整代碼

MainAbilitySlice的代碼如下:

  1. package com.xdw.album.slice; 
  2.  
  3. import com.xdw.album.MainAbility; 
  4. import com.xdw.album.ResourceTable; 
  5. import ohos.aafwk.ability.AbilitySlice; 
  6. import ohos.aafwk.ability.DataAbilityHelper; 
  7. import ohos.aafwk.ability.DataAbilityRemoteException; 
  8. import ohos.aafwk.content.Intent; 
  9. import ohos.agp.components.Component; 
  10. import ohos.agp.components.Image; 
  11. import ohos.agp.components.TableLayout; 
  12. import ohos.agp.components.Text; 
  13. import ohos.agp.window.dialog.ToastDialog; 
  14. import ohos.bundle.IBundleManager; 
  15. import ohos.data.resultset.ResultSet; 
  16. import ohos.hiviewdfx.HiLog; 
  17. import ohos.hiviewdfx.HiLogLabel; 
  18. import ohos.media.image.ImageSource; 
  19. import ohos.media.image.PixelMap; 
  20. import ohos.media.image.common.Size
  21. import ohos.media.photokit.metadata.AVStorage; 
  22. import ohos.utils.net.Uri; 
  23.  
  24. import java.io.FileDescriptor; 
  25. import java.io.FileNotFoundException; 
  26. import java.util.ArrayList; 
  27.  
  28. public class MainAbilitySlice extends AbilitySlice { 
  29.     private static final String TAG = "MainAbilitySlice"
  30.     private static final HiLogLabel LABEL = new HiLogLabel(HiLog.DEBUG, 0, "TAG"); 
  31.     public static final int MY_PERMISSIONS_REQUEST_READ_USER_STORAGE = 0;   //自定義的一個權(quán)限請求識別碼,用于處理權(quán)限回調(diào) 
  32.     private TableLayout tlAlbum;    //定義表格布局,用來加載圖片控件 
  33.     private Text textLoading, textNum;  //定義正在加載文本,照片數(shù)量顯示文本 
  34.  
  35.     @Override 
  36.     public void onStart(Intent intent) { 
  37.         super.onStart(intent); 
  38.         super.setUIContent(ResourceTable.Layout_ability_main); 
  39.         MainAbility mainAbility = (MainAbility) getAbility(); 
  40.         mainAbility.setMainAbilitySlice(this); 
  41.         initView(); 
  42.         if (verifySelfPermission("ohos.permission.READ_USER_STORAGE") != IBundleManager.PERMISSION_GRANTED) { 
  43.             // 應(yīng)用未被授予權(quán)限 
  44.             if (canRequestPermission("ohos.permission.READ_USER_STORAGE")) { 
  45.                 // 是否可以申請彈框授權(quán)(首次申請或者用戶未選擇禁止且不再提示) 
  46.                 requestPermissionsFromUser( 
  47.                         new String[] { "ohos.permission.READ_USER_STORAGE" } , MY_PERMISSIONS_REQUEST_READ_USER_STORAGE); 
  48.             } else { 
  49.                 // 顯示應(yīng)用需要權(quán)限的理由,提示用戶進(jìn)入設(shè)置授權(quán) 
  50.                 new ToastDialog(getContext()).setText("請進(jìn)入系統(tǒng)設(shè)置進(jìn)行授權(quán)").show(); 
  51.             } 
  52.         } else { 
  53.             // 權(quán)限已被授予 
  54.             //加載顯示系統(tǒng)相冊中的照片 
  55.             showPhotos(); 
  56.         } 
  57.     } 
  58.  
  59.     @Override 
  60.     public void onActive() { 
  61.         super.onActive(); 
  62.     } 
  63.  
  64.     @Override 
  65.     public void onForeground(Intent intent) { 
  66.         super.onForeground(intent); 
  67.     } 
  68.  
  69.     private void initView() { 
  70.         //初始化相關(guān)UI組件 
  71.         tlAlbum = (TableLayout) findComponentById(ResourceTable.Id_tl_album); 
  72.         tlAlbum.setColumnCount(3);  //表格設(shè)置成3列 
  73.         textLoading = (Text) findComponentById(ResourceTable.Id_text_loading); 
  74.         textNum = (Text) findComponentById(ResourceTable.Id_text_num); 
  75.     } 
  76.  
  77.     //定義加載顯示圖片的方法 
  78.     public void showPhotos() { 
  79.         //先移除之前的表格布局中的所有組件 
  80.         tlAlbum.removeAllComponents(); 
  81.         //定義一個數(shù)組,用來存放圖片的id,它的size就是照片數(shù)量 
  82.         ArrayList<Integer> img_ids = new ArrayList<Integer>(); 
  83.         //初始化DataAbilityHelper,用來獲取系統(tǒng)共享數(shù)據(jù) 
  84.         DataAbilityHelper helper = DataAbilityHelper.creator(getContext()); 
  85.         try { 
  86.             //讀取系統(tǒng)相冊的數(shù)據(jù) 
  87.             ResultSet result = helper.query(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, nullnull); 
  88.             //根據(jù)獲取的數(shù)據(jù)覺得“正在加載”提示是否顯示 
  89.             if (result == null) { 
  90.                 textLoading.setVisibility(Component.VISIBLE); 
  91.             } else { 
  92.                 textLoading.setVisibility(Component.HIDE); 
  93.             } 
  94.             //遍歷獲取的數(shù)據(jù),來動態(tài)加載表格布局中的圖片組件 
  95.             while (result != null && result.goToNextRow()) { 
  96.                 //從獲取的數(shù)據(jù)中讀取圖片的id 
  97.                 int mediaId = result.getInt(result.getColumnIndexForName(AVStorage.Images.Media.ID)); 
  98.                 //生成uri,后面會根據(jù)uri獲取文件 
  99.                 Uri uri = Uri.appendEncodedPathToUri(AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI, "" + mediaId); 
  100.                 //獲取文件信息 
  101.                 FileDescriptor filedesc = helper.openFile(uri, "r"); 
  102.                 //定義一個圖片編碼參數(shù)選項用于設(shè)置相關(guān)編碼參數(shù) 
  103.                 ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions(); 
  104.                 decodingOpts.desiredSize = new Size(300, 300); 
  105.                 //根據(jù)文件信息生成pixelMap對象,該對象是設(shè)置Image組件的關(guān)鍵api 
  106.                 ImageSource imageSource = ImageSource.create(filedesc, null); 
  107.                 PixelMap pixelMap = imageSource.createThumbnailPixelmap(decodingOpts, true); 
  108.                 //構(gòu)造一個圖片組件并且設(shè)置相關(guān)屬性 
  109.                 Image img = new Image(MainAbilitySlice.this); 
  110.                 img.setId(mediaId); 
  111.                 img.setHeight(300); 
  112.                 img.setWidth(300); 
  113.                 img.setMarginTop(20); 
  114.                 img.setMarginLeft(20); 
  115.                 img.setPixelMap(pixelMap); 
  116.                 img.setScaleMode(Image.ScaleMode.ZOOM_CENTER); 
  117.                 //在表格布局中加載圖片組件 
  118.                 tlAlbum.addComponent(img); 
  119.                 HiLog.info(LABEL, "uri=" + uri); 
  120.                 img_ids.add(mediaId); 
  121.             } 
  122.         } catch (DataAbilityRemoteException | FileNotFoundException e) { 
  123.             e.printStackTrace(); 
  124.         } 
  125.         //完成照片數(shù)量的刷新,如果沒有照片,則在UI中顯示“沒有照片”的文本 
  126.         if (img_ids.size() > 0) { 
  127.             textLoading.setVisibility(Component.HIDE); 
  128.             textNum.setVisibility(Component.VISIBLE); 
  129.             textNum.setText("照片數(shù)量:" + img_ids.size()); 
  130.         } else { 
  131.             textLoading.setVisibility(Component.VISIBLE); 
  132.             textLoading.setText("沒有照片"); 
  133.             textNum.setVisibility(Component.HIDE); 
  134.         } 
  135.     } 
  136.  

 復(fù)制MainAbility的代碼如下:

  1. package com.xdw.album; 
  2.  
  3. import com.xdw.album.slice.MainAbilitySlice; 
  4. import ohos.aafwk.ability.Ability; 
  5. import ohos.aafwk.content.Intent; 
  6. import ohos.agp.window.dialog.ToastDialog; 
  7. import ohos.bundle.IBundleManager; 
  8.  
  9. import static com.xdw.album.slice.MainAbilitySlice.MY_PERMISSIONS_REQUEST_READ_USER_STORAGE; 
  10.  
  11. public class MainAbility extends Ability { 
  12.     private MainAbilitySlice mainAbilitySlice; 
  13.     @Override 
  14.     public void onStart(Intent intent) { 
  15.         super.onStart(intent); 
  16.         super.setMainRoute(MainAbilitySlice.class.getName()); 
  17.     } 
  18.  
  19.     @Override 
  20.     public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) { 
  21.         super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults); 
  22.         switch (requestCode) { 
  23.             case MY_PERMISSIONS_REQUEST_READ_USER_STORAGE: { 
  24.                 // 匹配requestPermissions的requestCode 
  25.                 if (grantResults.length > 0 
  26.                         && grantResults[0] == IBundleManager.PERMISSION_GRANTED) { 
  27.                     // 權(quán)限被授予之后做相應(yīng)業(yè)務(wù)邏輯的處理 
  28.                     mainAbilitySlice.showPhotos(); 
  29.                 } else { 
  30.                     // 權(quán)限被拒絕 
  31.                     new ToastDialog(getContext()).setText("權(quán)限被拒絕").show(); 
  32.                 } 
  33.                 return
  34.             } 
  35.         } 
  36.     } 
  37.  
  38.  
  39.     public MainAbilitySlice getMainAbilitySlice() { 
  40.         return mainAbilitySlice; 
  41.     } 
  42.  
  43.     public void setMainAbilitySlice(MainAbilitySlice mainAbilitySlice) { 
  44.         this.mainAbilitySlice = mainAbilitySlice; 
  45.     } 

 復(fù)制布局文件ability_main.xml代碼如下:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <DirectionalLayout 
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos" 
  4.     ohos:height="match_parent" 
  5.     ohos:width="match_parent" 
  6.     ohos:orientation="vertical"
  7.  
  8.     <Text 
  9.         ohos:id="$+id:text_loading" 
  10.         ohos:height="match_parent" 
  11.         ohos:width="match_parent" 
  12.         ohos:text="正在打開..." 
  13.         ohos:text_alignment="center" 
  14.         ohos:text_size="45fp"></Text> 
  15.  
  16.     <ScrollView 
  17.         ohos:height="600vp" 
  18.         ohos:width="match_parent" 
  19.         ohos:left_padding="25vp" 
  20.         > 
  21.  
  22.         <TableLayout 
  23.             ohos:id="$+id:tl_album" 
  24.             ohos:height="match_content" 
  25.             ohos:width="match_parent" 
  26.             > 
  27.  
  28.         </TableLayout> 
  29.     </ScrollView> 
  30.  
  31.     <Text 
  32.         ohos:id="$+id:text_num" 
  33.         ohos:height="match_content" 
  34.         ohos:width="match_content" 
  35.         ohos:text_alignment="center" 
  36.         ohos:text_size="20fp"></Text> 
  37.  
  38. </DirectionalLayout> 

 想了解更多內(nèi)容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

 

責(zé)任編輯:jianghua 來源: 鴻蒙社區(qū)
相關(guān)推薦

2015-12-30 10:29:40

Git協(xié)作流程詳解

2009-10-13 08:55:50

布線系統(tǒng)操作規(guī)范

2012-04-28 14:23:57

IDP

2024-07-09 08:48:38

2023-12-06 08:23:44

代理模式設(shè)計模式

2015-08-06 10:28:24

git規(guī)范流程

2023-04-18 08:52:35

模塊Python

2012-06-14 13:45:23

頂級域名域名gTLD

2021-09-13 06:43:36

UPS電源安裝

2019-11-07 14:46:09

數(shù)據(jù)庫MySQL命令

2020-09-16 19:30:29

內(nèi)存

2023-10-20 14:16:24

ArkUI動態(tài)申請授權(quán)

2022-03-07 16:46:03

HarmonyOS鴻蒙操作系統(tǒng)

2009-11-19 17:18:30

靜態(tài)路由動態(tài)路由

2021-07-06 06:26:43

動態(tài)計算圖GPU深度學(xué)習(xí)

2021-08-10 20:41:33

AndroidApp流程

2009-10-19 13:33:45

綜合布線施工規(guī)范

2010-01-05 09:35:07

.Net Framew

2009-09-01 10:37:51

C#項目代碼C#代碼規(guī)范

2021-08-09 06:57:41

CodeReview流程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號