<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      uniapp_01_實現打開文件管理

      關于uniapp實現app端文件管理

      • 前言
      • 安卓是如何實現的
      • uniapp中幾種實現方式
      • 文檔里需要用到的主要api介紹
      • 實現

      注: 可以先閱讀 [h5+ io操作](https://www.html5plus.org/doc/zh_cn/io.html) 在看本文章, 當時沒注意到io所以全調用的原生的包導致只能在安卓使用

      前言

      最近,用uniapp寫一個app,其中有個功能,需要訪問SDcard中的目錄和文件,在查閱uniapp官方文檔后,發現文檔給出的api不支持app端,只能用html5+native.js去獲取。于是,在踩了無數坑之后,就有了這篇記錄。
      

      安卓是如何實現的

      安卓針不同的版本實現的方法有所不同, Android 6 (API 23) 之前應用的權限在安裝時全部授予,運行時應用不再需要詢問用戶。在 Android 6.0 或更高版本對權限進行了分類,對某些涉及到用戶隱私的權限可在運行時根據用戶的需要動態授予

      Android 10

      1. 需要在 AndroidManifest.xml 中添加 android.permission.WRITE_EXTERNAL_STORAGE 和 android.permission.READ_EXTERNAL_STORAGE 進行權限申請。
      2. application 中設置 android:requestLegacyExternalStorage="true"
      3. 然后需要動態的請求權限

      Android 11

      1. 需要在 AndroidManifest.xml 中添加 android.permission.MANAGE_EXTERNAL_STORAGE
      2. 需要動態獲取權限
      3. 參考 android 11 獲取全部文件權限
      4. 參考 Android 10、11 存儲完全適配
      5. 參考 Android Q中文件沙盒模式讀寫文件 08-16
      6. 參考 Android開發之 permission動態權限獲取
      7. 參考 Android 獲取某個文件夾下的所有文件
      8. 參考 Java--getAbsolutePath()獲取絕對路徑和相對路徑getPath()getName()listFiles()

      uniapp中幾種實現方式

      1. 使用 web-view , 指向一個 html 文件, 在html文件里面用input實現
      2. 用 html5+和native.js
      3. 參考 HTML5+規范5+Specification

      文檔里需要用到的主要api介紹

      1. requestPermissions 獲取授權 !!!!此api十分重要,如果不用這個api獲取權限的話,就只能讀取沙盒或公共媒體文件夾里的文件, requestPermissions 需要傳入三個參數 第一個是權限數組,第二個成功回調方法,第三個是失敗回調
      2. runtimeMainActivity 我原本以為之只是獲取一個Activity實例后來才發現它相當于 Android中的 Context
      3. importClass 這個api是導入包的api 你可以到導入java包寫原生
      4. newObject 有了這個api感覺可以將 importClass 丟一邊去了,這個api是將導入和實例化合并了,第一次參數填要導入的包,第二個填實例化的需要傳遞的參數
      5. invoke 這個api是調用方法!!!十分重要
      6. IO IO模塊管理本地文件系統,用于對文件系統的目錄瀏覽、文件的讀取、文件的寫入等操作

      實現

      注:下面代碼如果有更好的實現方式或那里寫錯了,歡迎各位大佬在評論區指正

      1. 打開文件管理器

         // 獲取應用主Activity實例對象
         const MAIN = plus.android.runtimeMainActivity();
         const INTENT = plus.android.importClass('android.content.Intent'); // 導入 Intent 類
         const INTENT_OBJ = new INTENT(INTENT.ACTION_GET_CONTENT);
         INTENT_OBJ.addCategory(INTENT.CATEGORY_OPENABLE); // 創建分類
         INTENT_OBJ.setType("*/*"); // 設置類型, 任意類型 image/* video/* ....
         // intent.putExtra(Intent.EXTRA_MIME_TYPES, 'image/*'); 設置多個類型
         // intent.setDataAndType(mUri,"image/*"); 
         MAIN.onActivityResult = (requestCode, resultCode, data) => {
           // ... 選擇的文件data
         MAIN.startActivityForResult(INTENT_OBJ, 1); 
        
      2. 獲取外部存儲權限

          const permissionsList = [
            "android.permission.WRITE_EXTERNAL_STORAGE",
            "android.permission.READ_EXTERNAL_STORAGE"
          ];
          plus.android.requestPermissions(permissionsList,(e)=>{
            // ... 注: e里面包括了永久拒絕,拒絕,同意授權這些信息
          })
        
      3. 判斷安卓版本

            let Build = plus.android.importClass('android.os.Build');
            let isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        
      4. 判斷格式是否是uri類型的

          let DocumentsContract = plus.android.importClass('android.provider.DocumentsContract');
          // 判斷是否是這個格式的url content://com.android.providers.media.documents/document/image%3A82482
          let isSystemUri = DocumentsContract.isDocumentUri(MAIN, uri);
        
      5. 打開文件文件管理器選擇文件返回絕對路徑

          /**
           * TODO 系統自帶的文件管理器 中 最近/圖片/視頻。。。等直接獲取 codid會是類型+文件id 沒有之前的路徑 需要檢測添加
           * https://blog.csdn.net/qq_43278826/article/details/101672670
           * https://www.runoob.com/w3cnote/android-tutorial-intent-base.html
           * https://juejin.cn/post/7012108220982362149
           * @method openFileManager 打開系統文件管理器 選擇文件放回文件路徑
           * @description uniapp 沒有提供打開安卓文件管理器的api 必須使用 input 或 plus
           * */
          openFileManager:  function() {
            // platform 系統 browserVersion 系統版本
            const {platform, browserVersion} = uni.getSystemInfoSync();
            if(platform == 'android') {
              const Activity = plus.android.runtimeMainActivity(); // 獲取 Activity
              const Intent = plus.android.importClass("android.content.Intent"); // 導入 Intent
              let initen_new = new Intent(Intent.ACTION_GET_CONTENT, null); // 實例化 Intent 并允許 獲取的是所有本地文件 可設置文件格式用于限制
              initen_new.setType("*/*"); // 設置類型 */* 無類型限制
              initen_new.addCategory(Intent.CATEGORY_OPENABLE); // 
              Activity.startActivityForResult(initen_new, 1); // 啟動Activity 打開系統的文件管理器
              
              /**
               * onActivityResult 安卓中 用于從其他頁面返回時帶回數據
               * */
              Activity.onActivityResult = (requestCode, resultCode, data) => {
                // console.log("打開文件管理器后選擇的文件返回了", requestCode, resultCode, data); // 打開文件管理器后選擇的文件返回了
                const Uri = data.getData();
                plus.android.importClass(Uri);
                const DocumentsContract =plus.android.importClass("android.provider.DocumentsContract");
                const Build = plus.android.importClass('android.os.Build');
                let isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // 判斷安卓版本是否大于 4.4
                
                /**
                 * uri=content://com.android.providers.media.documents/document/image%3A293502  4.4以后
                 * uri=file:///storage/emulated/0/temp_photo.jpg
                 * uri=content://media/external/images/media/193968
                 *
                 * uri=content://media/external/images/media/13   4.4以前
                 */
                
                if(DocumentsContract.isDocumentUri(Activity, Uri)){
                  // 獲取文件類型和id
                  const DocId = DocumentsContract.getDocumentId(Uri);
                  const [Type, Id] = DocId.split(":"); // 解析出數字格式的id
                  // console.log("文件類型和id",Type, Id);
                  let authority = Uri.getAuthority(); // 
                  if(authority == "com.android.providers.media.documents") {
                    const MediaStore = plus.android.importClass('android.provider.MediaStore');
                    let contentUri = null;
                    let selection = "_id=?";
                    let selectionArgs = [Id];
                    
                    // TODO 有些文件夾下文件無法獲取uri應當是此處問題
                    switch(Type) {
                      case 'image': contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI ;break;
                      case 'video': contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI ;break;
                      case 'audio': contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI ;break;
                    }
                    this.getDataColumn(Activity, contentUri, selection, selectionArgs);
                  } else if(authority == "com.android.providers.downloads.documents"){
                    const ContentUris = plus.android.importClass('android.content.ContentUris');
                    let contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), parseInt(DocId));// 此處需要將文件id轉換成long類型的 不然返回的是null
                    this.getDataColumn(Activity, contentUri);
                  } else if(authority == "com.android.externalstorage.documents"){
                    const Environment = plus.android.importClass('android.os.Environment');
                    if("primary" == Type) {
                      console.log("類型為primary的文件地址:", `${Environment.getExternalStorageDirectory()}/${Id}`);
                    } else {
                      const System = plus.android.importClass('java.lang.System');
                      console.log("類型非primary的文件地址",`${System.getenv("SECONDARY_STORAGE")}/${Id}`);
                    }
                  }
                } else if("content" == Uri.getScheme()) {
                  this.getDataColumn(Activity, Uri);
                } else if("file" == Uri.getScheme()) {
                  console.log("文件路徑:", uri.getPath());
                }
              }
            }
            console.log("當前手機的系統是",platform);
          },
          /**
           * uri轉路徑轉換
           * @method getDataColumn uri轉路徑轉換
           * @param {Obejct} activity 安卓的實例
           * @param {Obejct} uri 獲取到的文件地址
           * @param {String} selection 
           * @param {Array} selectionArgs 文件的id數組
           * */
          getDataColumn: function(activity, uri, selection = null, selectionArgs = null) {
            /**
             * 官方,提供了兩個, 用來將絕對路徑和平臺路徑互相轉換的api
             * plus.io.convertAbsoluteFileSystem(path) 將平臺絕對路徑轉換成本地URL路徑
             * plus.io.convertLocalFileSystemURL(url) 本地URL路徑轉換成平臺絕對路徑
             * 絕對路徑符合各平臺文件路徑格式,通常用于Native.JS調用系統原生文件操作API,也可以在前面添加“file://”后在html頁面中直接使用。
             */
            plus.android.importClass(activity.getContentResolver());
            let cursor = activity.getContentResolver().query(uri, ['_data'], selection, selectionArgs, null);
            plus.android.importClass(cursor);
            if (cursor != null && cursor.moveToFirst()) {
              let column_index = cursor.getColumnIndexOrThrow('_data');
              let result = cursor.getString(column_index)
              cursor.close();
              uni.getFileInfo({
                filePath: result,
                success: (res) => {
                  console.log(res);
                }
              })
        
              return result;
            }
            return null;
          }
        
      6. 獲取用戶所有以安裝程序

          /**
           * @method getAllApply 獲取用戶所有已安裝程序
           * */
          getAllApply: function() {
            const main = plus.android.runtimeMainActivity(); // 此處相當于 context
            let pManager = plus.android.invoke(main, 'getPackageManager');
            let pInfo = plus.android.invoke(pManager, 'getInstalledPackages', 0);
            let total = plus.android.invoke(pInfo, 'size');
            // 遍歷獲取包名和應用名稱  
            for (let i = 0; i < total; i++) {
              // 獲取包名  
              let packName = plus.android.getAttribute(plus.android.invoke(pInfo, 'get', i), 'packageName');
              // 獲取包名對應的應用名  
              let obj = plus.android.invoke(pManager, 'getApplicationInfo', packName, 0);
              let appName = plus.android.invoke(pManager, 'getApplicationLabel', obj);
              console.log(packName, appName);
            }
          }
        
      7. 獲取根目錄

          /**
           * @method getRootSDCar 獲取手機外部存儲目錄
           * @description 用于獲取手機的外部存儲目錄
           * */
          getRootSDCar: function() {
            // .... 在只用之前一定要仙獲取權限 不然只能訪問到沙盒里的內容        
            // 獲取root目錄路徑
            const Environment = plus.android.importClass("android.os.Environment");
            // getExternalStorageDirectory 獲取外部存儲目錄即 SDCard
            // getRootDirectory 獲取 Android 的根目錄 即系統主目錄
            let data = Environment.getExternalStorageDirectory(); 
            let rootPath = plus.android.invoke(data, "getAbsolutePath");
            console.log("根目錄", rootPath);
          }
        
      8. 獲取絕對路徑

          /**
           * @method getAbsolutePath 獲取絕對路徑
           * */
          getAbsolutePath: function() {
        
            /*
              StorageEventListener中有onStorageStateChanged()方法,當sd卡狀態改變時,
               此方法會調用,對各狀態的判斷一般會用到Environment類,此類中包含的有關sd卡狀態的常量有:
              MEDIA_BAD_REMOVAL:        表明SDCard 被卸載前己被移除 
              MEDIA_CHECKING:           表明對象正在磁盤檢查 
              MEDIA_MOUNTED:            表明sd對象是存在并具有讀/寫權限 
              MEDIA_MOUNTED_READ_ONLY:  表明對象權限為只讀 
              MEDIA_NOFS:               表明對象為空白或正在使用不受支持的文件系統 
              MEDIA_REMOVED:            如果不存在 SDCard 返回 
              MEDIA_SHARED:             如果 SDCard 未安裝 ,并通過 USB 大容量存儲共享 返回 
              MEDIA_UNMOUNTABLE:        返回 SDCard 不可被安裝 如果 SDCard 是存在但不可以被安裝 
              MEDIA_UNMOUNTED:          返回 SDCard 已卸掉如果 SDCard 是存在但是沒有被安裝 
            */
           
            const main = plus.android.runtimeMainActivity(); // 此處相當于 context
            const Build = plus.android.importClass('android.os.Build');
            const Environment = plus.android.importClass("android.os.Environment");
            
            let state = Environment.getExternalStorageState(); // 返回sd卡狀態
            let isState = plus.android.invoke(state,'equals', Environment.MEDIA_MOUNTED);
            let dir = null;
            
            if(isState) {
              if(Build.VERSION.SDK_INT >= 29) {
                /*
                  DIRECTORY_MUSIC	          音樂存放
                  DIRECTORY_PODCASTS	      系統廣播
                  DIRECTORY_RINGTONES	      系統鈴聲
                  DIRECTORY_ALARMS	        系統提醒鈴聲
                  DIRECTORY_NOTIFICATIONS	  系統通知鈴聲
                  DIRECTORY_PICTURES	      圖片存放
                  DIRECTORY_MOVIES	        電影存放
                  DIRECTORY_DOWNLOADS	      下載
                  DIRECTORY_DCIM	          相機拍攝照片和視頻
                */
                // dir = main.getExternalFilesDir(Environment.DIRECTORY_MUSIC) // 獲取音樂;
                // dir = main.getDataDir(); // > data/形式的路徑
                // getDataDirectory
                dir = main.getExternalFilesDir(null); // 獲取當前app下面的flies文件夾
                this.path = plus.android.invoke(dir,"getAbsolutePath"); // 獲取絕對路徑
                console.log("獲取此應用下Flies文件夾路徑",plus.android.invoke(dir,"getAbsolutePath"));
                /*
                  // 獲得父目錄
                  this.filePath = plus.android.invoke(dir, "getParentFile");
                  console.log("父目錄",plus.android.invoke(this.filePath, "getName"));
                  
                  
                  // 擁有的文件
                  let child = plus.android.invoke(dir, "listFiles");
                  
                  for(let i = 0 ;i<child?.length;i++){
                    this.childPath.push(plus.android.invoke(child[i], "getAbsolutePath"))
                    
                    console.log("是子文件",plus.android.invoke(child[i], "getAbsolutePath"));
                  }
                */
              } else {
                dir = Environment.getRootDirectory()
              }
            }
          },
        
        
      9. 通過絕對路徑獲取此路徑下所有子文件 HTML5+ 實現

          plus.io.resolveLocalFileSystemURL(`/storage/emulated/0/`,(metadata)=>{
            // ... 需要獲取權限
            // metadata.isDirectory // 判斷是是否是文件夾
            // metadata.isFile();//判斷是是否是文件
            let directoryReader = metadata.createReader(); // 創建一個目錄對象 獲取下面的子文件
            directoryReader.readEntries((entries)=>{
            for (var i = 0; i < entries.length; i++) {
              console.log("文件信息:" + entries[i].name);
            }
          }, (err)=>{})
        
      10. 通過絕對路徑獲取此路徑下所有子文件 偏向與原生 實現

        getAllTheChildFiles: function(path){
          this.childPath = []
          const main = plus.android.runtimeMainActivity(); // 此處相當于 context
          const Build = plus.android.importClass('android.os.Build');
          
          // 判斷 sd卡狀態
          const Environment = plus.android.importClass("android.os.Environment");
          const state = Environment.getExternalStorageState();
          const isState = plus.android.invoke(state,'equals', Environment.MEDIA_MOUNTED);
          if(isState) {
            // 調用java File包實現
            // let File = plus.android.importClass("java.io.File");
            // let File_new = new File(metadata.toLocalURL());
            
            const File = plus.android.newObject("java.io.File", `${path}`); // 導入包并new這個類
            const exists = !plus.android.invoke(File, "exists"); // 判斷路徑是否存在
            if(exists) return;
            const listFiles = plus.android.invoke(File, "listFiles");// 獲取子文件列表
            this.filePath = `${path}`
            
            for(let i = 0; i<listFiles.length;i++){
              const name = `${plus.android.invoke(listFiles[i], "getName")}`;
              const isFile = plus.android.invoke(listFiles[i], "isDirectory");
            }
          }
        }
        
        
      posted @ 2022-11-09 00:26  tsuru  閱讀(3324)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 色偷偷偷久久伊人大杳蕉| 亚洲色www成人永久网址| 人人人爽人人爽人人av| 国产对白老熟女正在播放| 久久人妻无码一区二区三区av| 婷婷久久香蕉五月综合加勒比 | 天天爱天天做天天爽夜夜揉| 中文字幕亚洲男人的天堂| 国产成人精彩在线视频| 国产l精品国产亚洲区| 免费观看激色视频网站| 国产精品中文字幕自拍| 国产成人精品av| 日韩一区二区三区无码a片| 天天躁日日躁狠狠躁2018| 欧美色综合天天久久综合精品| 亚洲精品尤物av在线网站| 无码免费大香伊蕉在人线国产| 暖暖影院日本高清...免费| 亚洲一区二区三区丝袜| 亚洲中文字幕国产精品| 中国女人大白屁股ass| 国产又色又爽又高潮免费| 99精品热在线在线观看视| 乐安县| 日韩内射美女人妻一区二区三区| 97精品伊人久久大香线蕉APP| 鹤岗市| 国产啪视频免费观看视频 | 亚洲国产精品综合久久网络| 亚洲AV无码一二区三区在线播放| 亚洲精品一区二区三区片| 久久精品国产99国产精品| 夜夜夜高潮夜夜爽夜夜爰爰| 国精偷拍一区二区三区| 欧美午夜精品久久久久久浪潮 | 蜜桃视频在线观看网站免费| 亚洲人成网线在线播放VA| 亚洲爆乳成av人在线视菜奈实| 九色国产精品一区二区久久| 亚洲欧洲色图片网站|