Android辅助H5做一个Web版的相册功能

Posted 汤米粥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android辅助H5做一个Web版的相册功能相关的知识,希望对你有一定的参考价值。

主要是两个功能,返回相册列表给H5,和选中图片。
1.获取相册列表用伪造的图片http url,让H5容器先拿到列表,然后在img请求具体图片的时候使用shouldInterceptRequest拦截,再返回压缩的图片流。因为在获取列表的时候如果就都要返回图片的实体base64会很慢。

2.在选中某一个图片时返回真实未压缩的图片的base64
class TestActivity : AppCompatActivity() 
    var mUploadCallbackAboveL: ValueCallback<Array<Uri?>?>? = null
    var mUploadMessage: ValueCallback<Uri?>? = null
    private val REQUEST_LIST_CODE = 999
    private val REQUEST_BUY_VIP = 100  //去到会员页的requestCode都是100
    private var mProjectModel: MyProjectModel = MyProjectModel()
    private var mFrom = ""
    private var mWorkId = ""
    private var mTemplateId = ""
    private var mType = ""
    private var mUrl = ""
    private var title = ""
    private var showToolbar = false
    private var albumnList: LinkedHashMap<String, AlbumBean> = linkedMapOf() //相册列表+每个相册里的照片列表
    private var onlyAblumnList: ArrayList<OnlyAlbumBean> = arrayListOf()
    private var allPicList: ArrayList<ImageBean>? = arrayListOf()  //全部照片列表
    private var firstPagePictures: ArrayList<ImageBean>? = null  //第一页预加载

    val mGson = Gson()

    var isLoadComplete = false


    companion object 
        private var mClickTime: Long = 0

        @JvmStatic
        fun open(context: Context, url: String, title: String, showToolbar: Boolean) 
            if (System.currentTimeMillis() - mClickTime > 500) 
                mClickTime = System.currentTimeMillis()
                val intent = Intent(context, NetEditorActivity::class.java)
                intent.putExtra("url", url)
                intent.putExtra("from", "template")
                intent.putExtra("showToolbar", showToolbar)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                context.startActivity(intent)
            
        

        @JvmStatic
        fun open(context: Context, workId: String, type: String) 
            if (System.currentTimeMillis() - mClickTime > 500) 
                mClickTime = System.currentTimeMillis()
                val intent = Intent(context, NetEditorActivity::class.java)
                intent.putExtra("work_id", workId)
                intent.putExtra("type", type)
                intent.putExtra("from", "project")
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                context.startActivity(intent)
            
        
    

    private var enterTime: Long = 0
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        StatusBarUtil.setColor(this, Color.parseColor("#141414"))
        StatusBarUtil.setLightMode(this)
        ISNav.getInstance().init  context, path, imageView -> Glide.with(context!!).load(path).into(imageView) 
        setContentView(R.layout.activity_net_editor)
        enterTime = System.currentTimeMillis()
        initProject()
        val settings = wv_editor.settings
        settings.javascriptEnabled = true
        settings.allowFileAccess = true
        settings.allowContentAccess = true
        settings.domStorageEnabled = true
        settings.databaseEnabled = true

        wv_editor.setBackgroundColor(0)
        wv_editor.background.alpha = 0

        settings.setGeolocationEnabled(true)
        settings.setAppCacheEnabled(true)
        //允许webview对文件的操作
        settings.setAllowUniversalAccessFromFileURLs(true);
        settings.setAllowFileAccess(true);
        settings.setAllowFileAccessFromFileURLs(true);

        settings.userAgentString = settings.userAgentString + " HELLO_android/" + SystemUtil.getVersionCode(HelloApplicationLike.getContext())

//        wv_editor.loadUrl(
//            "$url/?page_id=$mWorkId&uid=$userManager.userId&works_type=$mType&env=$env&runtime=Android"
//        )

        //    !!!!  TO DO加一个参数,后面要删掉********************//
        Log.d("hello", "url:$mUrl")
//        mUrl = "http://192.168.70.220:7788/?token=24e5fad7114d4d8380e6d175c6ca04d1&page_id=QL21RX0HW602040976&uid=602040976&works_type=poster&env=staging&dev_dll=http://192.168.70.220:22111&debug_photo=true"
        wv_editor.loadUrl(mUrl + "&debug_photo=true")
        val api2 = JsCallback()
        wv_editor.addJavascriptInterface(
                api2,
                "nativeApi"
        )
        wv_editor.webViewClient = object : WebViewClient() 
            override fun onPageFinished(view: WebView, url: String?) 
                tv_common_title.postDelayed(Runnable  tv_common_title.text = view.title , 1000)
            

            override fun shouldInterceptRequest(webview: WebView?, webResourceRequest: WebResourceRequest): WebResourceResponse? 

                var input: FileInputStream

                var url = webResourceRequest.getUrl().toString();

                var key = "storage/emulated";

                var host = MkHost.getInstance().getCommonWapHost()
                host = host.substring(0, host.length - 1)

                Log.e("xxx-host", host)

                /*如果请求包含约定的字段 说明是要拿本地的图片*/
                if (url.contains(key)) 
                    Log.e("xxx", "请求图片" + url + ":" + System.currentTimeMillis())
                    var imgPath = url.replace(host, "");
                    try 
                        /*重新构造WebResourceResponse  将数据已流的方式传入*/

                        var response: WebResourceResponse? = null

                        Log.e("xxx", "开始压缩图片" + url + ":" + System.currentTimeMillis())
                        //压缩图片
                        val options = BitmapFactory.Options()
                        options.inJustDecodeBounds = true
                        BitmapFactory.decodeFile(imgPath, options)
                        val inSampleSize = BitmapUtils.calculateInsampleSize(options, 200, 400)
                        options.inSampleSize = inSampleSize
                        options.inJustDecodeBounds = false
                        var bitmap = BitmapFactory.decodeFile(imgPath, options)

//                     Log.e("xxx", "开始压缩图片1" + url + ":" + System.currentTimeMillis())

                        val stream = ByteArrayOutputStream()
                        bitmap!!.compress(Bitmap.CompressFormat.JPEG, 100, stream)
                        var bis = ByteArrayInputStream(stream.toByteArray())
                        response = WebResourceResponse("image/jpg", "UTF-8", bis);

//                        Log.e("xxx", "开始压缩图片2" + url + ":" + System.currentTimeMillis())

//                        Log.e("xxx", "返回图片" + url + ":" + System.currentTimeMillis())
                        return response;
                     catch (e: Exception) 
                        e.printStackTrace();
                    

                
                return null
            
        


        // 自定义图片加载器
        ISNav.getInstance().init(ImageLoader  context: Context?, path: String?, imageView: ImageView? -> Glide.with(context!!).load(path).into(imageView!!) )


        wv_editor.webChromeClient = object : WebChromeClient() 

            override fun onConsoleMessage(consoleMessage: com.tencent.smtt.export.external.interfaces.ConsoleMessage?): Boolean 

                //获取log的级别

                when (consoleMessage?.messageLevel()) 
                    //将error信息上报到服务端
                    com.tencent.smtt.export.external.interfaces.ConsoleMessage.MessageLevel.ERROR -> 
                        Log.e("editor_error", consoleMessage.message() + " at " + consoleMessage.sourceId() + ":" + consoleMessage.lineNumber())
                        val errorMsg = consoleMessage.message() + " at " + consoleMessage.sourceId() + ":" + consoleMessage.lineNumber()
                        Log.e("editor_error", DefaultUserRepo.getInstance().getLoginUid() ?: "")
                        Log.e("editor_error", mProjectModel.workId)
                        Log.e("editor_error", ((System.currentTimeMillis() - enterTime) / 1000).toString())

                        var params: HashMap<String, String?> = HashMap()
                        params.put("uid", DefaultUserRepo.getInstance().getLoginUid())
                        params.put("id", mProjectModel?.workId)
                        params.put("time", ((System.currentTimeMillis() - enterTime) / 1000).toString())

                        var helloLog: HelloLogErrorBean = HelloLogErrorBean("error", "wap editor", "", GsonUtils.toJson(params), errorMsg)
                        HelloLogManager.errorLog(helloLog)
                    
                
                return super.onConsoleMessage(consoleMessage);
            

            // Android > 5.0 调用这个方法
            override fun onShowFileChooser(
                    webView: WebView?,
                    valueCallback: ValueCallback<Array<Uri?>?>?,
                    fileChooserParams: FileChooserParams?
            ): Boolean 
                mUploadCallbackAboveL = valueCallback
                choosePicture()
                return true
            

            // Android > 4.1.1 调用这个方法
            override fun openFileChooser(
                    uploadMsg: ValueCallback<Uri?>?,
                    acceptType: String?, capture: String?
            ) 
                mUploadMessage = uploadMsg
                choosePicture()
            

            // 3.0 + 调用这个方法
            fun openFileChooser(
                    uploadMsg: ValueCallback<Uri?>?,
                    acceptType: String?
            ) 
                mUploadMessage = uploadMsg
                choosePicture()
            

            // Android < 3.0 调用这个方法
            fun openFileChooser(uploadMsg: ValueCallback<Uri?>?) 
                mUploadMessage = uploadMsg
                choosePicture()
            
        
    

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) 
        super.onActivityResult(requestCode, resultCode, data)
        // 图片选择结果回调
        if (requestCode == REQUEST_LIST_CODE && resultCode == RESULT_OK && data != null) 
            val pathList: ArrayList<String>? = data.getStringArrayListExtra("result")
            if (pathList != null && pathList.size > 0) 
                val result = Uri.parse("file://" + pathList[0])
                if (mUploadMessage != null) 
                    mUploadMessage!!.onReceiveValue(result)
                    mUploadMessage = null
                
                val results = arrayOf(result)
                if (mUploadCallbackAboveL != null) 
                    mUploadCallbackAboveL!!.onReceiveValue(results)
                    mUploadCallbackAboveL = null
                
            
        

        //会员页购买成功,刷新编辑器
        if (requestCode == REQUEST_BUY_VIP && resultCode == RESULT_OK) 
            Log.e("xxx", "刷新")
            wv_editor.reload()
        

        if (resultCode == RESULT_CANCELED || data == null) 
            if (mUploadMessage != null) 
                mUploadMessage!!.onReceiveValue(null)
                mUploadMessage = null
            
            if (mUploadCallbackAboveL != null) 
                mUploadCallbackAboveL!!.onReceiveValue(null)
                mUploadCallbackAboveL = null
            
        

        //从结算列表页面过来
        if (requestCode == RequestCodes.EDITOR_BUY_MATERIALS && resultCode == RESULT_OK) 
            Log.e("xxx", "去到分享")
            wv_editor.reload() //刷新编辑器
            routeToSharePoster(mWorkId)
        
    

    private fun initProject() 
        mFrom = intent.extras?.getString("from") ?: ""
        mTemplateId = intent.extras?.getString("template_id") ?: ""
        mWorkId = intent.extras?.getString("work_id") ?: ""
        mType = intent.extras?.getString("type") ?: ""
        mUrl = intent.extras?.getString("url") ?: ""
        showToolbar = intent.extras?.getBoolean("showToolbar", false) ?: false
        Log.d("hellolog", "mUrl:$mUrl")

//        mUrl = "https://hellopicture.oss-cn-beijing.aliyuncs.com/app_common/android_ab/js_demo.html"   //测试网页

        if (showToolbar) 
            layout_common_title.visibility = View.VISIBLE

            fl_common_back.setOnClickListener 
                finish()
            
         else 
            layout_common_title.visibility = View.GONE
        

        mProjectModel.workId = mWorkId
        mProjectModel.type = mType
        val userManager = UserManager.getInstance()
        mProjectModel.uid = userManager.userId
    

    private var mHandler: Handler? = Handler()

    private fun choosePicture() 
        val config = ISListConfig.Builder()
                .multiSelect(false)
                .rememberSelected(false)
                .statusBarColor(Color.parseColor("#141414"))
                .backResId(R.mipmap.icon_new_back)
                .title("选择图片")
                .titleColor(Color.WHITE)
                .titleBgColor(Color.parseColor("#141414"))
                .needCrop(false)
                .needCamera(true)
                .maxNum(1)
                .build()
        ISNav.getInstance().toListActivity(this, config, REQUEST_LIST_CODE)

//        Log.e("xxx-", "查看相册")
//        PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
//                object : PermissionsResultAction() 
//                    override fun onGranted() 
                        mUploadCallbackAboveL!!.onReceiveValue(getSystemPhotoList(this@NetEditorActivity))
//                        ToastUtil.showSuccess("获取相册成功")
//                    
//
//                    override fun onDenied(permission: String) 
//                        ToastUtil.showFailMessage("请在系统权限设置中找到HELLO开启存储权限")
//                        mUploadCallbackAboveL!!.onReceiveValue(arrayOf())
//                    
//                )


    

    class ImageBean(var image: String?, var assetId: String?)

    /**
     *  start 开始位置
     *  limit 一页数量
     *  albumn 相册目录
     */
    fun getPhotoList(context: Context, start: Int, limit: Int, albumn: String): ArrayList<ImageBean>? 


        val result: ArrayList<ImageBean> = arrayListOf()

        val uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI

        val contentResolver: ContentResolver = context.contentResolver
        val cursor: Cursor = contentResolver.query(uri, null, null, null, MediaStore.Images.ImageColumns.DATE_ADDED + " DESC")!!


//        val uri: Uri = MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI
//
//        val projection = arrayOf<String>(MediaStore.Images.Thumbnails._ID, MediaStore.Images.Thumbnails.IMAGE_ID, MediaStore.Images.Thumbnails.DATA)
//
//
//        val contentResolver: ContentResolver = context.contentResolver
//        val cursor: Cursor = contentResolver.query(uri, projection, null, null,null)!!
        if (cursor == null || cursor.getCount() <= 0) return null // 没有图片
        var position = 0
        cursor.moveToPosition(start)

        var host = MkHost.getInstance().getCommonWapHost()
        host = host.substring(0, host.length - 1)
        while (cursor.moveToNext() && position < limit) 
            val index: Int = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
            val path: String = cursor.getString(index) // 文件地址

            //压缩图片
            val options = BitmapFactory.Options()
            options.inJustDecodeBounds = true
            BitmapFactory.decodeFile(path, options)
            val inSampleSize = BitmapUtils.calculateInsampleSize(options, 240, 480)
            options.inSampleSize = inSampleSize
            options.inJustDecodeBounds = false
            var bitmap = BitmapFactory.decodeFile(path, options)

            //将Bitmap换成流传给H5
            val stream = ByteArrayOutputStream()
            bitmap!!.compress(Bitmap.CompressFormat.JPEG, 100, stream)
            result.add(ImageBean("data:image/jpeg;base64," + Base64.encodeToString(stream.toByteArray(), Base64.DEFAULT).replace("\\n", ""), path))
            Log.e("xxx-$position", path)
            position++
        
        cursor.close()

//        else 
//            var list = File(albumn).listFiles()  // list null 不允许这样遍历,拿不到子目录内容
//            list?.forEach 
//                result.add(ImageBean("http://192.168.70.220:7788" + it, ""))
//            
//        

        return result
    


    private fun getPhotoListNew(start: Int, limit: Int, albumn: String): ArrayList<ImageBean>? 
        var picList: ArrayList<ImageBean> = arrayListOf()

        var position = 0

        var inputStream: InputStream? = null

        if (albumn.isNullOrEmpty()) 
            var image: ImageBean? = null
            while (position < limit) 
                if (allPicList == null || start + position >= allPicList?.size!!) 
                    break
                
                image = allPicList?.get(start + position)
//                val base64Str = getSmallImageAndBase64(image?.assetId!!)
//                image?.image = base64Str
                picList?.add(image!!)
                position++
            
         else 
            //选中的相册
            var list = albumnList[albumn]
            var image: ImageBean? = null
            while (position < limit) 
                if ((start + position) < 0 || start + position >= list!!.images!!.size) break
                image = list!!.images?.get(start + position)!!
                picList?.add(image)
                position++
            
        
        return picList
    

    private fun getSmallImageAndBase64(imagePath: String?): String 

        Log.e("xxx-", "开始压缩图片:" + imagePath)
        var base64ImageStr: String? = null
        //压缩图片
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeFile(imagePath, options)
        val inSampleSize = BitmapUtils.calculateInsampleSize(options, 240, 480)
        options.inSampleSize = inSampleSize
        options.inJustDecodeBounds = false
        var bitmap = BitmapFactory.decodeFile(imagePath, options)

        //将Bitmap换成流传给H5
        val stream = ByteArrayOutputStream()
        bitmap!!.compress(Bitmap.CompressFormat.JPEG, 50, stream)
        Log.e("xxx-", "结束压缩图片:" + imagePath)

        Log.e("xxx-", "开始base64图片:" + imagePath)
        base64ImageStr = "data:image/jpeg;base64," + Base64.encodeToString(stream.toByteArray(), Base64.DEFAULT).replace("\\n", "")

        //把缩略图存起来?

        Log.e("xxx-", "结束base64图片:" + imagePath)
        return base64ImageStr
    

    private fun fileBase64String(path: String): String? 
        return try 
            val fis = FileInputStream(path) //转换成输入流
            val baos = ByteArrayOutputStream()
            val buffer = ByteArray(1024)
            var count = 0
            while (fis.read(buffer).also  count = it  >= 0) 
                baos.write(buffer, 0, count) //读取输入流并写入输出字节流中
            
            fis.close() //关闭文件输入流
            return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT).replace("\\n", "")
         catch (e: java.lang.Exception) 
            null
        
    


    override fun onBackPressed() 
//        val jsonObject = JSONObject()
//        val userInfo = UserInfo()
//        userInfo.token = UserManager.getInstance().token
//        userInfo.uid = UserManager.getInstance().userId
//        jsonObject.put("type", "NATIVE")
//        jsonObject.put("userInfo", userInfo)
//        val shareStr = "'type': 'HORouter', 'data':'url': 'vip' "
//        JS_MESSAGE_MODEL(shareStr)

//        bridgeBack()

//        val shareStr = "'type': 'HORouter', 'params':'url': 'hello://home/vip/vipActivity' "
//        val shareStr = "'type': 'HORouter', 'params':'url': 'hello://posterShare?width=720&height=1280&previewUrl=www.baidu.com' "

//        APP_INVOKE(shareStr)
        if (isLoadComplete) 
            bridgeBack()
         else 
//            finish()
        
    

    private fun bridgeBack() 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
            wv_editor.evaluateJavascript("window.onJsBridgeBack()") 
                if (it != "false") 
                    finish()
                
            
        
    

    private fun routeToSharePosterWatermark(workId: String = "") 
        mWorkId = workId
        val api = NetworkProvider.getInstance().provide(HttpApi::class.java)
        api.getWorkDetail2(UserManager.getInstance().userId, mWorkId)
                .compose(RxUtils.ioMain())
                .subscribe(object : DefaultObserver<MyProjectModel?>() 
                    override fun onFailure(throwable: Throwable) 
                    override fun onSubscribe(d: Disposable) 
                    override fun onNext(myProjectModel: MyProjectModel) 
                        mProjectModel = myProjectModel
                        PosterImagePreviewSavedActivity.open(
                                this@NetEditorActivity,
                                false,
                                mProjectModel.templateId,
                                mProjectModel.title,
                                mProjectModel.categoryId,
                                mProjectModel.secondaryCategoryId,
                                mProjectModel.spec,
                                mProjectModel,
                        )
                    
                )
    

    private fun routeToSharePoster(workId: String = "") 
        mWorkId = workId
        val api = NetworkProvider.getInstance().provide(HttpApi::class.java)
        api.getWorkDetail2(UserManager.getInstance().userId, mWorkId)
                .compose(RxUtils.ioMain())
                .subscribe(object : DefaultObserver<MyProjectModel?>() 
                    override fun onFailure(throwable: Throwable) 
                    override fun onSubscribe(d: Disposable) 
                    override fun onNext(myProjectModel: MyProjectModel) 
                        mProjectModel = myProjectModel
                        Router.getInstance()
                                .build(RouterConstants.PROJECT_POSTER_SETTING_ACTIVITY)
                                .with(Bundle().apply 
                                    putParcelable(EXTRA_DATA, mProjectModel)
                                    putBoolean(EXTRA_IS_FROM_SETTING, true)
                                )
                                .navigation()
                    
                )
    

    private fun routeToShareH5(workId: String = "") 
        mWorkId = workId
        val api = NetworkProvider.getInstance().provide(HttpApi::class.java)
        api.getWorkDetail2(UserManager.getInstance().userId, mWorkId)
                .compose(RxUtils.ioMain())
                .subscribe(object : DefaultObserver<MyProjectModel?>() 
                    override fun onFailure(throwable: Throwable) 
                    override fun onSubscribe(d: Disposable) 
                    override fun onNext(myProjectModel: MyProjectModel) 
                        mProjectModel = myProjectModel
                        Router.getInstance()
                                .build(RouterConstants.PROJECT_SETTING_ACTIVITY)
                                .with(Bundle().apply 
                                    putParcelable(EXTRA_DATA, mProjectModel)
                                    putBoolean(EXTRA_IS_FROM_SETTING, true)
                                    putString("title", "分享作品")
                                )
                                .withString("from", "")
                                .navigation()
                    
                )
    

    private fun routeToShareH5Clear(workId: String = "") 
        mWorkId = workId
        val api = NetworkProvider.getInstance().provide(HttpApi::class.java)
        api.getWorkDetail2(UserManager.getInstance().userId, mWorkId)
                .compose(RxUtils.ioMain())
                .subscribe(object : DefaultObserver<MyProjectModel?>() 
                    override fun onFailure(throwable: Throwable) 
                    override fun onSubscribe(d: Disposable) 
                    override fun onNext(myProjectModel: MyProjectModel) 
                        mProjectModel = myProjectModel
                        Router.getInstance()
                                .build(RouterConstants.PROJECT_SETTING_ACTIVITY)
                                .with(Bundle().apply 
                                    putParcelable(EXTRA_DATA, mProjectModel)
                                    putBoolean(EXTRA_IS_FROM_SETTING, true)
                                    putString("title", "分享作品")
                                )
                                .withString("from", "")
                                .navigation()
                    
                )
    

    fun testShare(para: String) 

        val jsonType = object : TypeToken<ShareInfo>() .type
        val shareInfo = mGson.fromJson<ShareInfo>(para, jsonType)


        if (shareInfo.type == "wechat") 
            ShareUtil.shareUrlToWxNoImage(this@NetEditorActivity, shareInfo.url, shareInfo.title, shareInfo.content, shareInfo.isCircle
                    ?: false)
        
    


    fun saveBase64Image(base64: String?) 

        val camara = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
        // 首先保存图片
        // 首先保存图片
        var appDir = File(camara, "HELLO")
        if (!appDir.exists()) 
            val success = appDir.mkdirs()
            if (!success) 
                appDir = camara
            
        
        if (!appDir.exists()) 
            throw RuntimeException(getString(R.string.msg_error_save_to_gallery))
        

        PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                object : PermissionsResultAction() 
                    override fun onGranted() 
                        BitmapUtils.saveBase64ToFile(this@NetEditorActivity, base64, appDir.absolutePath)
                    

                    override fun onDenied(permission: String) 
                        ToastUtil.showFailMessage("保存失败!因为没有读写SD卡权限\\n请在系统权限设置中找到HELLO开启存储权限")
                    
                )

    


    inner class JsCallback() 

        @JavascriptInterface
        fun APP_INVOKE(para: String) 
            try 
                Log.d("hellolog", "para:$para")

                val type1 = object : TypeToken<JsPara>() .type
                val object1 = mGson.fromJson<JsPara>(para, type1)
                when (object1.type) 
                    "HORouter" -> 
                        val type2 = object : TypeToken<RoutePara>() .type
                        val object2 = mGson.fromJson<RoutePara>(object1.params, type2)

                        object2.url?.let 
                            val tempUri = it.toUri()
                            when (tempUri.host + tempUri.path) 
                                "home/vip/vipActivity" -> 

                                    var senior = tempUri.getQueryParameter("is_senior")
                                    var forward_page_name = tempUri.getQueryParameter("forward_page_name");
                                    var forward_module = tempUri.getQueryParameter("forward_module")

                                    VipTrackParam.forward_module = forward_module ?: ""
                                    VipTrackParam.forward_page_name = forward_page_name ?: ""
                                    VipTrackParam.vip_page_type = senior ?: "true"

                                    JumpUtil().openVipPageForResult(this@NetEditorActivity, true, "", false, null, REQUEST_BUY_VIP)

                                
                                "posterShare" -> 

                                    routeToSharePoster(
                                            tempUri.getQueryParameter("workId") ?: mWorkId,
                                    )
                                
                                "posterShareWatermark" -> 
                                    routeToSharePosterWatermark(
                                            tempUri.getQueryParameter("workId") ?: mWorkId,
                                    )
                                
                                "h5Share" -> 
                                    routeToShareH5(tempUri.getQueryParameter("workId") ?: mWorkId)
                                
                                "h5Clear" -> 
                                    routeToShareH5Clear(tempUri.getQueryParameter("workId")
                                            ?: mWorkId)
                                
                                "support.qq.com/products/162011/" -> 
                                    CommonWebViewActivity.openPost(this@NetEditorActivity, "https://support.qq.com/products/162011/", "意见反馈")
                                
                                "materialShoppingList" -> 
                                    val workId = tempUri.getQueryParameter("workId") ?: mWorkId
                                    if (!workId.isNullOrEmpty()) 
                                        mWorkId = workId
                                    

                                    val templateType = tempUri.getQueryParameter("templateType")
                                    val forward_page_name = tempUri.getQueryParameter("editor")
                                    var previewUrl: String? = ""

                                    mType = templateType ?: ""
                                    if ("poster".equals(templateType)) 
                                     else 
                                        previewUrl = tempUri.getQueryParameter("previewUrl")
                                    

                                    val repository = MaterialsPurchaseRepository.newInstance()
                                    var observable: Observable<List<MaterialPurchase>> = repository.getAllNeedPurchaseMaterialsNewEditor(workId)
                                    observable.compose(RxUtils.ioMain())
                                            .doOnSubscribe  disposable: Disposable? -> 
                                            .subscribe(object : DefaultObserver<List<MaterialPurchase?>?>() 
                                                override fun onFailure(throwable: Throwable) 
                                                

                                                override fun onSubscribe(d: Disposable) 

                                                

                                                override fun onNext(materialPurchases: List<MaterialPurchase?>) 
                                                    if (materialPurchases.isNotEmpty()) 
                                                        MaterialsPurchaseActivity.Companion.openForResult(
                                                                "new_editor",
                                                                this@NetEditorActivity,
                                                                workId,
                                                                mType,
                                                                materialPurchases!! as List<MaterialPurchase>,
                                                                RequestCodes.EDITOR_BUY_MATERIALS,
                                                                EditorTrackUtil.getCommonParamsJsonFromEditorModel(mProjectModel),
                                                                previewUrl ?: ""
                                                        )
                                                     else 
                                                        routeToShareH5(tempUri.getQueryParameter("workId")
                                                                ?: mWorkId)
                                                    
                                                
                                            )

                                
                                else -> 
                                    if (it.contains("https")) 
                                        var url = URLDecoder.decode(it)
                                        NetEditorActivity.open(this@NetEditorActivity, url, "", true)
                                    
                                
                            
                        

                    
                    "HOLifecycle" -> 

                    
                    "HOShare" -> 
                        val type2 = object : TypeToken<ShareInfo>() .type
                        val object2 = mGson.fromJson<ShareInfo>(object1.params, type2)
                        if (object2.type == "wechat") 
                            ShareUtil.shareUrlToWxNoImage(
                                    this@NetEditorActivity,
                                    object2.url,
                                    object2.title,
                                    object2.content,
                                    object2.isCircle ?: false
                            )
                        
                    
                    "HOToast" -> 
                        val type2 = object : TypeToken<ToastPara>() .type
                        val object2 = mGson.fromJson<ToastPara>(object1.params, type2)
                        ToastUtil.showNormalMessage(object2.message ?: "")
                    
                    "HOBack" -> 
                        finish()
                    
                    "HOUserInfo" -> 
                        var userInfo: UserInfo? = null
                        if (DefaultUserRepo.getInstance().getUserVips().isEmpty()) 

                            userInfo = UserInfo(
                                    token = UserManager.getInstance().token,
                                    uid = UserManager.getInstance().userId
                            ).copy()
                         else 
                            userInfo = UserInfo(
                                    token = UserManager.getInstance().token,
                                    uid = UserManager.getInstance().userId,
                                    vipInfo = DefaultUserRepo.getInstance().getVipEntrance(
                                            HelloConfigUtils.isInABGroup(HelloConfigUtils.VIP_POSITION), HelloConfigUtils.isInABGroup(
                                            HelloConfigUtils.VIP_STRENGTHEN_MONTHLY_PRICE
                                    )
                                    ).copy()
                            )
                        

                        val callbackStr = object1.jsCbFnName ?: ""
                        val js = "window.$callbackStr($mGson.toJson(userInfo))"

                        Log.e("xxx-", js)
                        runOnUiThread 
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                                wv_editor.evaluateJavascript(js, null)
                            
                        
                    
                    "HOAppVersion" -> 
                        val callbackStr = object1.jsCbFnName ?: ""
                        val js = "window.$callbackStr(\\"version\\":\\"$SystemUtil.getVersionName(this@NetEditorActivity)\\")"

                        Log.e("xxx-", js)
                        runOnUiThread 
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                                wv_editor.evaluateJavascript(js, null)
                            
                        
                    
                    "HOVibrate" -> 
                        val type2 = object : TypeToken<VibratePara>() .type
                        val object2 = mGson.fromJson<VibratePara>(object1.params, type2)
                        VibrateUtil.vibrate(this@NetEditorActivity, object2.time ?: 50L)
                    

                    "HOSaveImage" -> 
                        val type2 = object : TypeToken<SaveImage>() .type
                        val object2 = mGson.fromJson<SaveImage>(object1.params, type2)
                        if (object2?.url != null) 
                            var str = object2.url!!.split(",")
                            saveBase64Image(str[1])
                        
                    
                    "HOAlbumList" -> 
                        Log.e("xxx", "HOAlbumList")
                        val callbackStr = object1.jsCbFnName ?: ""

                        /**
                         *
                         *     Android装载器Loader是从Android 3 引入的 ,使用相关API 可以从数据库,网络,内容管理者等数据源中加载数据,然后显示在 Fragment 或 Activity上
                         *
                         *     Loader在单独的线程上运行,以防止 UI 出现卡顿或无响应。
                         *
                         *     Loader通过在事件发生时提供回调方法来简化线程管理。
                         *
                         *     Loader在配置更改中持久保存和缓存结果,以防止重复查询。
                         *
                         *     Loader可以实现一个观察者来监控底层数据源的变化。例如,CursorLoader自动注册一个ContentObserver以在数据更改时触发重新加载。
                         *
                         */
                        val mLoaderCallback: LoaderManager.LoaderCallbacks<Cursor?> = object : LoaderManager.LoaderCallbacks<Cursor?> 
                            private val IMAGE_PROJECTION = arrayOf(
                                    MediaStore.Images.Media.DATA,
                                    MediaStore.Images.Media.DISPLAY_NAME,
                                    MediaStore.Images.Media._ID)

                            override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor?> 
                                if (id == 0) 
                                    return CursorLoader(this@NetEditorActivity,
                                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION,
                                            null, null, MediaStore.Images.Media.DATE_ADDED + " DESC")
                                 else 
                                    return CursorLoader(this@NetEditorActivity,
                                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, IMAGE_PROJECTION[0] + " not like '%.gif%'", null, MediaStore.Images.Media.DATE_ADDED + " DESC")
                                
                            

                            override fun onLoadFinished(loader: Loader<Cursor?>, data: Cursor?) 
                                if (data != null) 

                                    var host = MkHost.getInstance().getCommonWapHost()
                                    host = host.substring(0, host.length - 1)


                                    val count = data.count
                                    Log.e("xxx", "照片分类开始")
                                    albumnList.clear()
                                    allPicList?.clear()
                                    if (count > 0) 
                                        data.moveToFirst()
                                        do 
                                            //第一步:imageId,第二步:获取thumUri  第三步:获取缩略图
                                            val image = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[0]))
                                            val name = data.getString(data.getColumnIndexOrThrow(IMAGE_PROJECTION[1]))
                                            val imageId = data.getLong(data.getColumnIndexOrThrow(IMAGE_PROJECTION[2]))

//                                            val thumbUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageId)

//                                            Log.e("xxx-", "thumUri = " + thumbUri)

                                            // Load thumbnail of a specific media item.
//                                            val thumbnail: Bitmap? =
//                                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) 
//                                                        contentResolver.loadThumbnail(thumbUri, Size(240, 480), null)
//                                                     else 
//                                                        null
//                                                    
                                            val path = File(image).parentFile.absolutePath
                                            if (!albumnList.containsKey(path)) 
                                                val albumBeanDefault = AlbumBean()
                                                albumBeanDefault.albumId = ""
                                                albumBeanDefault.count = count.toLong()
                                                albumBeanDefault.name = "所有照片"
                                                albumBeanDefault.image = image
                                                albumnList["所有照片"] = albumBeanDefault

                                                val albumBean = AlbumBean()
                                                albumBean.albumId = path
                                                albumBean.count = 1
                                                albumBean.name = path.substring(path.lastIndexOf("/") + 1, path.length)
                                                albumBean.image = image

                                                Log.e("xxx-创建相册", albumBean.name)

                                                albumnList[path] = albumBean
                                             else 
                                                albumnList[path]?.count = albumnList[path]?.count!! + 1
                                            
                                            //将相册照片分类
                                            albumnList[path]?.images?.add(ImageBean(image, image))

                                            Log.e("xxx-相册", albumnList[path]?.name + "添加相片" + image)

                                            allPicList?.add(ImageBean(host + image, image))

                                         while (data.moveToNext())
                                    
                                    Log.e("xxx", "照片分类结束")

                                    var onlyAlbumBean: OnlyAlbumBean? = null
                                    onlyAblumnList.clear()
                                    albumnList.forEach 
                                        onlyAlbumBean = OnlyAlbumBean(it.value.name, it.value.albumId, it.value.count, it.value.image)
                                        onlyAblumnList.add(onlyAlbumBean!!)
                                    
                                    val js = "window.$callbackStr($mGson.toJson(onlyAblumnList))"
                                    Log.e("xxx-AlbumList", js)
                                    runOnUiThread 
                                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                                            wv_editor.evaluateJavascript(js, null)
                                        
                                    
                                
                            

                            override fun onLoaderReset(loader: Loader<Cursor?>) 

                            
                        

                        if (albumnList == null || albumnList.size == 0) 
                            mHandler?.post 
                                supportLoaderManager.initLoader(0, null, mLoaderCallback)
                            
                         else 
                            var onlyAlbumBean: OnlyAlbumBean? = null
                            albumnList.forEach 
                                onlyAlbumBean = OnlyAlbumBean(it.value.name, it.value.albumId, it.value.count, it.value.image)
                                onlyAblumnList.add(onlyAlbumBean!!)
                            
                            val js = "window.$callbackStr($mGson.toJson(onlyAblumnList))"
                            Log.e("xxx-AlbumList", js)
                            runOnUiThread 
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                                    wv_editor.evaluateJavascript(js, null)
                                
                            
                        
                    
                    "HOPhotoList" -> 

                        Log.e("xxx", "HOPhotoList")
                        val callbackStr = object1.jsCbFnName ?: ""

                        val type2 = object : TypeToken<PhotoBean>() .type
                        val object2 = mGson.fromJson<PhotoBean>(object1.params, type2)


                        var start = object2.start
                        var limit = object2.limit
                        var albumn = object2.albumId

                        if (ContextCompat.checkSelfPermission(this@NetEditorActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE) !== PackageManager.PERMISSION_GRANTED) 
                            ActivityCompat.requestPermissions(this@NetEditorActivity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_LIST_CODE)
                         else 
                            Log.e("xxx-", "获取图片列表开始:" + System.currentTimeMillis())
                            var tempList: ArrayList<ImageBean>? = null
                            tempList = getPhotoListNew(start, limit, albumn ?: "")
//                            var list = BitmapUtils.getAllPicturesThumnail(this@NetEditorActivity)
//                            BitmapUtils.getThumnailList(this@NetEditorActivity)
                            var response: StringBuffer = StringBuffer()
                            response.append("[")
                            tempList?.forEachIndexed  index, imageBean ->
                                response.append("\\"image\\":")
                                response.append("\\"$imageBean.image\\",")
                                response.append("\\"assetId\\":")
                                response.append("\\"$imageBean.assetId\\"")
                                response.append("")
                                if (index < tempList.size - 1) 
                                    response.append(",")
                                
                            
                            response.append("]")
                            val js = "window.$callbackStr($response)"
                            Log.e("xxx-", "获取图片列表结束:" + System.currentTimeMillis())
                            Log.e("xxx-", js)
                            runOnUiThread 
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                                    wv_editor.evaluateJavascript(js, null)
                                
                            
                        
                    

                    "HOPhotoSelected" -> 

                        val callbackStr = object1.jsCbFnName ?: ""

                        val type2 = object : TypeToken<SelectedPhotoBean>() .type
                        val object2 = mGson.fromJson<SelectedPhotoBean>(object1.params, type2)

                        var file = File(object2.assetId)
                        var fileInputStream = FileInputStream(file)
                        var response = ""
                        if (object2.assetId != null) 
                            response = "data:image/jpeg;base64," + fileBase64String(object2.assetId!!)
                        
                        val js = "window.$callbackStr(\\"originData\\":\\"$response\\")"
                        Log.e("xxx-", "获取图片列表结束:" + System.currentTimeMillis())
                        Log.e("xxx-", js)
                        runOnUiThread 
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                                wv_editor.evaluateJavascript(js, null)
                            
                        

                    
                    "HOAlbumAuthStatus" -> 
                        val granted = if (PermissionsManager.getInstance().hasAllPermissions(this@NetEditorActivity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE))) 1 else 0
                        val callbackStr = object1.jsCbFnName ?: ""
                        val js = "window.$callbackStr(\\"authorized\\":\\"$granted.toString()\\")"

                        runOnUiThread 
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                                wv_editor.evaluateJavascript(js, null)
                            
                        
                    
                    "HOAlbumAuthSetting" -> 
                        PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(this@NetEditorActivity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                                object : PermissionsResultAction() 
                                    override fun onGranted() 
                                        val callbackStr = object1.jsCbFnName ?: ""
                                        val js = "window.$callbackStr(\\"authorized\\":\\"1\\")"

                                        runOnUiThread 
                                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
                                                wv_editor.evaluateJavascript(js, null)
                                            
                                        
                                    

                

以上是关于Android辅助H5做一个Web版的相册功能的主要内容,如果未能解决你的问题,请参考以下文章

web调用手机相册,并实现动态增加图片功能

Android:支持多选的本地相册

Android-混合开发H5 能直接调起原生的相册和相机吗?

Android-混合开发H5 能直接调起原生的相册和相机吗?

H5调用本地相册/相机上传图片

html5怎样调用手机摄像头或者相册?