flutter_inappwebview的使用與問(wèn)題解決方案

  • 前情摘要

Q1:\color{OrangeRed}{flutter中是否有類(lèi)似原生的WebView控件}
A1:Flutter沒(méi)有類(lèi)似WebView控件留搔,借助平臺(tái)層實(shí)現(xiàn)WebView功能迫靖。
Q2:\color{OrangeRed}{flutter中如何使用WebView加載網(wǎng)頁(yè)}
A2:借助現(xiàn)網(wǎng)提供的WebView插件即可實(shí)現(xiàn)網(wǎng)絡(luò)加載,其中flutter_inappwebview插件非常優(yōu)秀扇雕,推薦使用码邻。
Q3:\color{OrangeRed}{flutter的WebView如何與js通信的}
A3:InAppWebView已經(jīng)實(shí)現(xiàn)了一套完整的js通信機(jī)制,如果用官方WebView插件旋讹,則需要自己實(shí)現(xiàn)一套JsBridge同時(shí)適用Android和iOS殖蚕,成本稍高一點(diǎn)。
Q4:\color{OrangeRed}{flutter中WebView是如何實(shí)現(xiàn)}
A4:Flutter本身不提供WebView功能沉迹,通過(guò)PlatformView去適用各個(gè)平臺(tái)已有的WebView能力睦疫,降低了實(shí)現(xiàn)成本

webview_flutter:功能一般,滿(mǎn)足基本功能需求鞭呕,官方出品持續(xù)完善中蛤育。(不支持H5上傳圖片)
flutter_inappwebview:功能非常豐富,文檔非常完善,屬于三方庫(kù)中的精品瓦糕,推薦使用底洗。
flutter_webview_plugin:功能不夠完善,現(xiàn)有功能將積極合入webview_flutter咕娄,后續(xù)不在維護(hù)亥揖,不建議使用。
flutter_inappbrowser: 已停止維護(hù)

  • webview_flutter 是官方維護(hù)的 WebView 插件圣勒,特性是基于原生和 Flutter SDK 封裝费变,繼承 StatefulWidget,因此支持內(nèi)嵌于 Flutter Widget 樹(shù)中圣贸,這是比較靈活的挚歧。但不支持https自制證書(shū)強(qiáng)制信任。
  • flutter_webview_plugin 則是基于原生 WebView 封裝的 Flutter 插件吁峻,將原生的一些基本使用 API 封裝好提供給 Flutter 調(diào)用滑负,因此并不能內(nèi)嵌于 Flutter Widget 樹(shù)中,因此在界面的跳轉(zhuǎn)必須得先釋放掉用含,返回后又要重新初始化矮慕,所以顯示會(huì)有很多限制性。
  • flutter_inappwebview 與其他WebView插件相比耕餐,它的功能 非常豐富:有很多事件 凡傅、 方法 和 選項(xiàng) 可以用來(lái)控制WebView。此外肠缔,前者沒(méi)有提供很好的API文檔,或者至少是文檔不完整哼转。相比之下明未, flutter_inappwebview 的每個(gè)特性幾乎都有文檔記錄。
webview.jpg
對(duì)比.png
  • 使用flutter_inappwebview出現(xiàn)的問(wèn)題

場(chǎng)景:下面是webview中最常見(jiàn)的 需要彈出picker壹蔓,有拍照和選擇相冊(cè)功能的例子

upimage.png

image.png

問(wèn)題

  1. 相機(jī)權(quán)限默認(rèn)是禁止的趟妥。直接跳轉(zhuǎn)到相冊(cè)。
  2. 開(kāi)啟相機(jī)權(quán)限佣蓉,閃退披摄。
  3. 授權(quán)被拒絕后,無(wú)法再?gòu)棾鍪跈?quán)
  4. 無(wú)法直接跳轉(zhuǎn)到相機(jī)拍照
  • 問(wèn)題解決

\color{brown}{<問(wèn)題1勇凭、2>}
在設(shè)置中開(kāi)啟相機(jī)權(quán)限后疚膊,再點(diǎn)擊按鈕,報(bào)如下錯(cuò)誤:

error.png

解決方法為:在project->app->android->app->src->mian里的 AndroidManifest.xml 的 application 中添加下面代碼

 <provider
           android:name="androidx.core.content.FileProvider"
           android:authorities="${applicationId}.flutter_inappwebview.fileprovider"
           android:exported="false"
           android:grantUriPermissions="true"
           >
           <meta-data
               android:name="android.support.FILE_PROVIDER_PATHS"
               android:resource="@xml/provider_paths" />
       </provider>

添加以上代碼后虾标,在相機(jī)權(quán)限開(kāi)啟的情況下寓盗,能正常彈出選擇彈框了。


1.gif

\color{brown}{<問(wèn)題3>}
但是默認(rèn)是禁止的,點(diǎn)擊按鈕無(wú)反應(yīng)傀蚌。
查看如下文件中的 startPhotoPickerIntent 方法:

image.png

startPhotoPickerIntent.png

正常邏輯:首次進(jìn)入基显,獲取相機(jī)授權(quán),允許訪(fǎng)問(wèn)善炫,則彈出picker選擇框撩幽,禁止訪(fǎng)問(wèn),則下次再進(jìn)入跳轉(zhuǎn)到設(shè)置開(kāi)啟箩艺。

所以修改代碼如下:

 Activity activity = inAppBrowserDelegate != null ? inAppBrowserDelegate.getActivity() : plugin.activity;

    if (!needsCameraPermission()) {
      if (acceptsImages(acceptTypes)) {
        extraIntents.add(getPhotoIntent());
      }
      if (acceptsVideo(acceptTypes)) {
        extraIntents.add(getVideoIntent());
      }
    } else {
      //動(dòng)態(tài)獲取權(quán)限
      boolean hasrefuse = ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA);
        //選擇了禁止或拒絕
      if (hasrefuse){
            /**跳轉(zhuǎn)到設(shè)置中去開(kāi)啟**/
        Intent settingsIntent = new Intent();
        settingsIntent.setAction(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        settingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
        settingsIntent.setData(android.net.Uri.parse("package:" + activity.getPackageName()));
        settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        settingsIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);

        activity.startActivity(settingsIntent);
        return false;
      }else {
        //獲取授權(quán)
        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, 100);
        return false;
      }
    }

效果如下:

1.gif
2.gif
  • 關(guān)于shouldShowRequestPermissionRationale

shouldShowRequestPermissionRationale窜醉,回到最初的解釋“\color{OrangeRed}{應(yīng)不應(yīng)該解釋下}\color{green}{請(qǐng)求這個(gè)權(quán)限的目的}”。
1.都\color{blue}{沒(méi)有請(qǐng)求過(guò)這個(gè)權(quán)限}舅桩,用戶(hù)不一定會(huì)拒絕你酱虎,所以你不用解釋?zhuān)史祷?img class="math-inline" src="https://math.jianshu.com/math?formula=%5Ccolor%7Bbrown%7D%7Bfalse%7D" alt="\color{brown}{false}" mathimg="1">;
2.\color{blue}{請(qǐng)求了但是被拒絕了},此時(shí)返回\color{brown}{true}擂涛,意思是你該向用戶(hù)好好解釋下了读串;
3.\color{blue}{請(qǐng)求權(quán)限被禁止了},也不給你彈窗提醒了撒妈,所以你也不用解釋了恢暖,故返回\color{brown}{false};
4.\color{blue}{請(qǐng)求被允許了},都給你權(quán)限了狰右,還解釋個(gè)啥杰捂,故返回\color{brown}{false}

shouldShowRequestPermissionRationale的功能價(jià)值何在

在此之前先說(shuō)明下棋蚌,由于不同的系統(tǒng)廠商定制的結(jié)果嫁佳,
1.有的手機(jī)某些權(quán)限清單注冊(cè)了權(quán)限就能用,不用動(dòng)態(tài)申請(qǐng)(因?yàn)橄到y(tǒng)會(huì)在安裝時(shí)自動(dòng)app分配一些權(quán)限谷暮,具體怎么分配的這里暫不做討論)蒿往;
2.有的手機(jī)在彈出授權(quán)時(shí)選擇拒絕就默認(rèn)了不再?gòu)棾觯?br> 3.有的沿用了原生系統(tǒng)的規(guī)則;
4.設(shè)置-應(yīng)用-權(quán)限中權(quán)限分“允許湿弦、詢(xún)問(wèn)瓤漏、拒絕”三個(gè)級(jí)別,但是有的權(quán)限只有“允許颊埃、拒絕”兩個(gè)級(jí)別蔬充;

這里先統(tǒng)一下名詞:
允許 – 權(quán)限通過(guò)
拒絕–拒絕了但是還允許詢(xún)問(wèn)
禁止–拒絕了且不再允許詢(xún)問(wèn)(如4中所述的“拒絕”先定義為禁止)

不同的系統(tǒng)廠商定制的結(jié)果,
所以在測(cè)試時(shí)發(fā)現(xiàn)班利,比如RealMe手機(jī)和華為Android系統(tǒng)在權(quán)限被拒絕后
ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)返回的的結(jié)果為true饥漫,華為鴻蒙系統(tǒng)在被禁止后返回為false。符合上面藍(lán)色字體的解釋肥败。
詳情請(qǐng)看:shouldShowRequestPermissionRationale的詳細(xì)分析

但是上面所寫(xiě)的獲取權(quán)限的判斷邏輯趾浅,明顯在手機(jī)為華為鴻蒙系統(tǒng)(只有允許愕提、禁止)的時(shí)候,禁止后會(huì)再次走到授權(quán)方法皿哨,然而在禁止后浅侨,授權(quán)就不會(huì)再?gòu)棾隽恕?/p>

所以,應(yīng)對(duì)不同機(jī)型的情況证膨,在再次授權(quán)的事件里重寫(xiě)onRequestPermissionsResult方法如输,根據(jù)返回的requestCode結(jié)果在里面做處理。按邏輯來(lái)講央勒,應(yīng)該在如下圖的地方添加判斷做處理不见,無(wú)奈各種報(bào)錯(cuò)無(wú)法處理。如果有解決的同學(xué)請(qǐng)告知我崔步,謝謝稳吮。

RequestPermissionHandler.png

所以,
在project->app->android->app->src->mian->MainActivity.kt中添加如下代碼:

  override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<String?>,
            grantResults: IntArray
    ) {
        when (requestCode) {
            100 -> {
                if (grantResults.size > 0) {
                    if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                        val pref1 = getSharedPreferences("data", MODE_PRIVATE)
                        val account = pref1.getBoolean("hasDENIED", false)
                        //是否已經(jīng)被拒絕了
                        if (account) {
                            val settingsIntent = Intent()
                            settingsIntent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                            settingsIntent.addCategory(Intent.CATEGORY_DEFAULT)
                            settingsIntent.data = Uri.parse("package:" + activity.packageName)
                            settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                            settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
                            settingsIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                            startActivity(settingsIntent)
                        }else{
                            pref1.edit().putBoolean("hasDENIED", true).commit()
                        }
                        Log.d("JumpChannel", "被拒絕了")
                    }
                    // 權(quán)限被用戶(hù)同意井濒,可以做你要做的事情了灶似。
                } else {
                    // 權(quán)限被用戶(hù)拒絕了,可以提示用戶(hù),關(guān)閉界面等等瑞你。

                }
                return
            }
        }
    }

\color{brown}{<問(wèn)題4>}
由于H5可能用的框架不一酪惭,所以參考下面兩篇文章添加對(duì)應(yīng)屬性:
文章1

<input type="file" accept="image/*" capture>

文章2

<input type="file" accept="image/*" capture="camera">

Github的Demo地址:flutter_inappwebview_demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市者甲,隨后出現(xiàn)的幾起案子春感,更是在濱河造成了極大的恐慌,老刑警劉巖虏缸,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲫懒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡刽辙,警方通過(guò)查閱死者的電腦和手機(jī)刀疙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)扫倡,“玉大人,你說(shuō)我怎么就攤上這事竟纳∧炖#” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵锥累,是天一觀的道長(zhǎng)缘挑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)桶略,這世上最難降的妖魔是什么语淘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任诲宇,我火速辦了婚禮,結(jié)果婚禮上惶翻,老公的妹妹穿的比我還像新娘姑蓝。我一直安慰自己,他們只是感情好吕粗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布纺荧。 她就那樣靜靜地躺著,像睡著了一般颅筋。 火紅的嫁衣襯著肌膚如雪宙暇。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天议泵,我揣著相機(jī)與錄音占贫,去河邊找鬼。 笑死先口,一個(gè)胖子當(dāng)著我的面吹牛型奥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播池充,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼桩引,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了收夸?” 一聲冷哼從身側(cè)響起坑匠,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卧惜,沒(méi)想到半個(gè)月后厘灼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咽瓷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年设凹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茅姜。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡闪朱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钻洒,到底是詐尸還是另有隱情奋姿,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布素标,位于F島的核電站称诗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏头遭。R本人自食惡果不足惜寓免,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一癣诱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧袜香,春花似錦撕予、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至疾就,卻和暖如春澜术,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猬腰。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工鸟废, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人姑荷。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓盒延,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鼠冕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子添寺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容