基於Xamarin Android實現的簡單的瀏覽器


  最近做了一個Android瀏覽器,當然功能比較簡單,主要實現了自己想要的一些功能……現在有好多瀏覽器為什么還要自己寫?當你使用的時候總有那么一些地方不如意,於是就想自己寫一個。

  開發環境:Xamarin Android(非Forms)+聯想機子(5.0)+榮耀機子(8.0)

  【開發目標】

  1、瀏覽器的基本功能,關聯Http和Https(在另一個APP中打開網頁時,可以彈出本應用)

  2、創建應用目錄,用來存放離線網頁文件

  3、可以離線保存網頁(格式為mht)

  4、關聯mht和mhtml格式的文件

  【涉及到的技術點】

  1、重寫Activity中的OnBackPressed方法,實現webview回退和再按一次退出程序的功能

  2、重寫Activity中的OnConfigurationChanged方法,實現橫豎屏功能

  【webview相關技術點】

  1、開啟一些常用的設置:JavaScriptEnabled、DomStorageEnabled(如果DomStorageEnabled不啟用,網頁中的下拉刷新和加載更多將不起作用;例子:百度首頁加載新聞)

  2、重寫WebViewClient中的ShouldOverrideUrlLoading方法,在點擊打開網頁中的鏈接時,用自己的webview中打開連接,而不是打開其他的瀏覽器

  3、重寫WebChromeClient中的OnReceivedTitle和OnProgressChanged方法,分別獲取頁面標題(作為離線文件的名稱)和加載進度

  4、采用事件的方式,通知主Activity關於頁面加載開始、加載結束、標題、加載進度等的一些事情,進而更新UI(這里和Java的寫法有些不同)

  5、頁面加載進度條

  【懸浮按鈕】1、全屏(退出)按鈕  2、保存網頁  3、掃描二維碼(版本兼容問題尚未實現)

  【網址輸入框】

  1、輸入正確的網址之后點擊輸入法中的“前往”調轉

  2、隱藏輸入法

  以上列到的功能基本實現,最后在榮耀V10上測試時,其他的功能還好,就是在打開離線文件時也不報錯,就是打不開……郁悶啊!最后查了一下也沒有找到原因。這里說一下場景,以方便大神發現問題,希望大神不吝賜教。在我的聯想手機上測試時發現本地文件路徑是這樣的:file:///storage/emulated/0/DDZMyBrowser/SavePages/1.mht  此時可以正常瀏覽,而V10中得到的路徑是這樣的,內部存儲:content://com.huawei.hidisk.fileprovider/root/storage/emulated/0/DDZMyBrowser/SavePages/1.mht   SD卡:content://com.huawei.hidisk.fileprovider/root/storage/0ABF-6213/1.mht  這兩個都打不開。我查詢的結果,這路徑應該是利用FileProvider生成的(7.0以上),哎,並非真正的android開發,並不太懂,一臉懵逼,不知道是不是因為這個原因……開始我還寄希望於將content://轉為file:///格式的,但是都失敗了,最后想想網上說的webview支持content://開頭的啊,自己在輸入框中手動修改為:file:///storage/emulated/0/DDZMyBrowser/SavePages/1.mht  發現是可以征程瀏覽的……

  上一下截圖:

  1、應用首頁

  2、再按一次退出程序

  3、橫屏

  4、豎屏

  5、網頁中的下拉刷新

  6、加載更多

  7、用自己的webview中打開連接,而不是打開其他的瀏覽器;進度條

  8、全屏

  9、離線保存

  10、關聯MHT

  11、關聯HTTP和HTTPS

   12、actionGo

   13、最后再來一張V10加載異常的圖片

   去去去,傳上去之后發現圖片太大了,全是百度的圖片……這事兒弄得

  最后在貼一下代碼,記錄一下

  CS代碼:

  1 using Android.App;
  2 using Android.Widget;
  3 using Android.OS;
  4 using Android.Webkit;
  5 using System;
  6 using Android.Support.Design.Widget;
  7 using Android.Content;
  8 using Android.Views;
  9 using Java.IO;
 10 using Android.Views.InputMethods;
 11 using Android.Content.PM;
 12 using Android.Content.Res;
 13 using Android.Provider;
 14 using Android.Database;
 15 
 16 namespace DDZ.MyBrowser
 17 {
 18     /// <summary>
 19     /// 獲取網頁Title
 20     /// </summary>
 21     /// <param name="title"></param>
 22     public delegate void MyWebViewTitleDelegate(string title);
 23 
 24     /// <summary>
 25     /// 獲取網頁加載進度
 26     /// </summary>
 27     public delegate void MyWebViewProgressChangedDelegate(int newProgress);
 28 
 29     /// <summary>
 30     /// 網頁加載完成事件
 31     /// </summary>
 32     public delegate void MyWebViewPageFinishedDelegate();
 33 
 34     [IntentFilter(
 35         new[] { Intent.ActionView },
 36         Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
 37         DataSchemes = new[] { "http", "https" })]
 38     [IntentFilter(
 39         new[] { Intent.ActionView },
 40         Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
 41         DataSchemes = new[] { "file", "content" }, DataMimeType = "*/*", DataHost = "*", DataPathPattern = ".*\\\\.mhtml")]
 42     [IntentFilter(
 43         new[] { Intent.ActionView },
 44         Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
 45         DataMimeType = "*/*", DataSchemes = new[] { "file", "content" }, DataHost = "*", DataPathPattern = ".*\\\\.mht")]
 46     [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true,
 47         ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.KeyboardHidden)]
 48     public class MainActivity : Activity
 49     {
 50         WebView myBrowser;
 51         EditText edtTxtUrl;
 52         FloatingActionButton fabMain;
 53         FloatingActionButton fabSubQRcodeScan;
 54         FloatingActionButton fabSubToggleFullScreen;
 55         FloatingActionButton fabSubSaveMHT;
 56         ProgressBar myBrowserPBar;
 57 
 58         private static bool isFabOpen;
 59         private static bool isFullScreen;
 60         private static DateTime lastClickGoBack = DateTime.Now;
 61 
 62         private static string currentPageTitle;
 63         private readonly string externalStorageDirPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
 64         private readonly string selfFolderName = "DDZMyBrowser";
 65         private static string selfApplicationDirPath;
 66         protected override void OnCreate(Bundle savedInstanceState)
 67         {
 68             // https://blog.csdn.net/niunan/article/details/71774292
 69             base.OnCreate(savedInstanceState);
 70             // Set our view from the "main" layout resource
 71             SetContentView(Resource.Layout.activity_main);
 72 
 73             //  1、瀏覽器控件相關
 74             myBrowser = FindViewById<WebView>(Resource.Id.myBrowser);
 75             //  要與Javascript交互,則webview必須設置支持Javascript
 76             myBrowser.Settings.JavaScriptEnabled = true;
 77             //  支持通過JS打開新窗口 
 78             myBrowser.Settings.JavaScriptCanOpenWindowsAutomatically = true;
 79             myBrowser.Settings.DomStorageEnabled = true;
 80             myBrowser.Settings.AllowFileAccessFromFileURLs = true;
 81 
 82             var myWebViewClient = new MyWebViewClient();
 83             myWebViewClient.GetWebViewPageFinishedDelegate += MyWebViewClient_GetWebViewPageFinishedDelegate;
 84             myBrowser.SetWebViewClient(myWebViewClient);
 85             var myWebChromeClient = new MyWebChromeClient();
 86             myWebChromeClient.GetWebViewTitleDelegate += MyWebChromeClient_GetWebViewTitleDelegate;
 87             myWebChromeClient.GetWebViewProgressChangedDelegate += MyWebChromeClient_GetWebViewProgressChangedDelegate;
 88             myBrowser.SetWebChromeClient(myWebChromeClient);
 89             edtTxtUrl = FindViewById<EditText>(Resource.Id.edtTxtUrl);
 90             edtTxtUrl.EditorAction += EdtTxtUrl_EditorAction;
 91             myBrowserPBar = FindViewById<ProgressBar>(Resource.Id.myBrowserPBar);
 92 
 93             //  2、右下方懸浮控件
 94             fabMain = FindViewById<FloatingActionButton>(Resource.Id.fabMain);
 95             fabSubQRcodeScan = FindViewById<FloatingActionButton>(Resource.Id.fabSubQRcodeScan);
 96             fabSubToggleFullScreen = FindViewById<FloatingActionButton>(Resource.Id.fabSubToggleFullScreen);
 97             fabSubSaveMHT = FindViewById<FloatingActionButton>(Resource.Id.fabSubSaveMHT);
 98             fabMain.Click += FabMain_Click;
 99             fabSubQRcodeScan.Click += FabSubQRcodeScan_Click;
100             fabSubToggleFullScreen.Click += FabSubToggleFullScreen_Click; ;
101             fabSubSaveMHT.Click += FabSubSaveMHT_Click;
102 
103             //  3、第三方應用使用該應用打開網頁時,"this.Intent.DataString" 獲取需要打開的網址
104             //      自己打開時,"this.Intent.DataString" 的值為空
105             String url = this.Intent.DataString;
106             if (!String.IsNullOrEmpty(url))
107             {              
108                 if (this.Intent.Data.Scheme == "content")
109                 {
110                     //  DocumentsContract.IsDocumentUri(this, this.Intent.Data):false
111 
112                     //  this.Intent.Data.Authority:com.huawei.hidisk.fileprovider
113                     //  this.Intent.Data.Host:com.huawei.hidisk.fileprovider
114                     //  this.Intent.Data.Path:/root/storage/0ABF-6213/xxx.mht
115                     //  this.Intent.Data.PathSegments:this.Intent.Data.Path的數組形式
116 
117                     //  Android.Support.V4.Content.FileProvider.GetUriForFile()
118                     //   this.Intent.SetFlags(ActivityFlags.GrantReadUriPermission).SetFlags(ActivityFlags.GrantWriteUriPermission);
119                 }
120             }
121             edtTxtUrl.Text = url;
122             LoadOnePage(url);
123 
124             //  4、創建應用目錄
125             CreateSelfApplicationFolder();
126         }       
127 
128         private void EdtTxtUrl_EditorAction(object sender, TextView.EditorActionEventArgs e)
129         {
130             string inputUrl = edtTxtUrl.Text.Trim();
131             if (e.ActionId == ImeAction.Go)
132             {
133                 HideSoftInputFn();
134                 LoadOnePage(inputUrl);
135             }
136         }
137 
138         #region 獲取WebView加載頁面相關信息的一些自定義事件
139         private void MyWebViewClient_GetWebViewPageFinishedDelegate()
140         {
141             Toast.MakeText(this, "加載完成", ToastLength.Long).Show();
142         }
143 
144         private void MyWebChromeClient_GetWebViewProgressChangedDelegate(int newProgress)
145         {
146             myBrowserPBar.Visibility = ViewStates.Visible;
147             myBrowserPBar.Progress = newProgress;
148             if (newProgress == 100)
149             {
150                 myBrowserPBar.Visibility = ViewStates.Gone;
151             }
152         }
153 
154         private void MyWebChromeClient_GetWebViewTitleDelegate(string title)
155         {
156             currentPageTitle = title;
157         }
158         #endregion
159 
160         #region 懸浮按鈕
161         private void FabMain_Click(object sender, EventArgs e)
162         {
163             if (!isFabOpen)
164             {
165                 HideSoftInputFn();
166                 ShowFabMenu();
167             }
168             else
169             {
170                 CloseFabMenu();
171             }
172             SetToggleFullScreenBtnImg();
173         }
174 
175         private void FabSubQRcodeScan_Click(object sender, EventArgs e)
176         {
177             Toast.MakeText(this, "掃描二維碼", ToastLength.Long).Show();
178         }
179 
180         private void FabSubSaveMHT_Click(object sender, EventArgs e)
181         {
182             string savePageDirPath = $"{selfApplicationDirPath}{File.Separator}SavePages";
183             File dir = new File(savePageDirPath);
184             if (!dir.Exists())
185             {
186                 bool retBool = dir.Mkdir();
187             }
188             myBrowser.SaveWebArchive($"{savePageDirPath}{File.Separator}{currentPageTitle}.mht");
189         }
190 
191         private void FabSubToggleFullScreen_Click(object sender, EventArgs e)
192         {
193             if (isFullScreen)
194             {   //  目前為全屏狀態,修改為非全屏
195                 edtTxtUrl.Visibility = ViewStates.Visible;
196                 this.Window.ClearFlags(WindowManagerFlags.Fullscreen);
197             }
198             else
199             {   //  目前為非全屏狀態,修改為全屏
200                 edtTxtUrl.Visibility = ViewStates.Gone;
201                 this.Window.SetFlags(WindowManagerFlags.Fullscreen, WindowManagerFlags.Fullscreen);
202             }
203             isFullScreen = !isFullScreen;
204             SetToggleFullScreenBtnImg();
205         }
206 
207         private void ShowFabMenu()
208         {
209             isFabOpen = true;
210             fabSubQRcodeScan.Visibility = ViewStates.Visible;
211             fabSubToggleFullScreen.Visibility = ViewStates.Visible;
212             fabSubSaveMHT.Visibility = ViewStates.Visible;
213 
214             fabMain.Animate().Rotation(135f);
215             fabSubQRcodeScan.Animate()
216                .TranslationY(-600f)
217                .Rotation(0f);
218             fabSubToggleFullScreen.Animate()
219                .TranslationY(-410f)
220                .Rotation(0f);
221             fabSubSaveMHT.Animate()
222                 .TranslationY(-220f)
223                 .Rotation(0f);
224         }
225 
226         private void CloseFabMenu()
227         {
228             isFabOpen = false;
229 
230             fabMain.Animate().Rotation(0f);
231             fabSubQRcodeScan.Animate()
232                 .TranslationY(0f)
233                 .Rotation(90f);
234             fabSubToggleFullScreen.Animate()
235                 .TranslationY(0f)
236                 .Rotation(90f);
237             fabSubSaveMHT.Animate()
238                 .TranslationY(0f)
239                 .Rotation(90f);
240 
241             fabSubQRcodeScan.Visibility = ViewStates.Gone;
242             fabSubToggleFullScreen.Visibility = ViewStates.Gone;
243             fabSubSaveMHT.Visibility = ViewStates.Gone;
244         }
245 
246         private void SetToggleFullScreenBtnImg()
247         {
248             if (isFullScreen)
249             {
250                 fabSubToggleFullScreen.SetImageResource(Resource.Drawable.fullscreenExit);
251             }
252             else
253             {
254                 fabSubToggleFullScreen.SetImageResource(Resource.Drawable.fullscreen);
255             }
256         }
257         #endregion
258 
259         #region 重寫基類 Activity 方法
260         public override void OnConfigurationChanged(Configuration newConfig)
261         {
262             base.OnConfigurationChanged(newConfig);
263             if (newConfig.Orientation == Android.Content.Res.Orientation.Portrait)
264             {
265                 edtTxtUrl.Visibility = ViewStates.Visible;
266                 fabMain.Visibility = ViewStates.Visible;
267                 this.Window.ClearFlags(WindowManagerFlags.Fullscreen);
268                 isFullScreen = false;
269                 Toast.MakeText(Application.Context, "豎屏模式!", ToastLength.Long).Show();
270             }
271             else
272             {
273                 CloseFabMenu();
274                 edtTxtUrl.Visibility = ViewStates.Gone;
275                 fabMain.Visibility = ViewStates.Gone;
276                 this.Window.SetFlags(WindowManagerFlags.Fullscreen, WindowManagerFlags.Fullscreen);
277                 isFullScreen = true;
278                 Toast.MakeText(Application.Context, "橫屏模式!", ToastLength.Long).Show();
279             }
280         }
281         public override void OnBackPressed()
282         {
283             if (myBrowser.CanGoBack())
284             {
285                 myBrowser.GoBack();
286             }
287             else
288             {
289                 if ((DateTime.Now - lastClickGoBack).Seconds > 2)
290                 {
291                     Toast.MakeText(this, $"再按一次退出程序", ToastLength.Long).Show();
292                     lastClickGoBack = DateTime.Now;
293                 }
294                 else
295                 {
296                     this.Finish();
297                 }
298             }
299         }
300         #endregion
301 
302         private void LoadOnePage(String url = "")
303         {
304             currentPageTitle = null;
305             if (String.IsNullOrEmpty(url)) url = "https://www.baidu.com/";
306             myBrowser.LoadUrl(url);
307         }
308 
309         private void HideSoftInputFn()
310         {
311             //  隱藏鍵盤
312             InputMethodManager imm = (InputMethodManager)this.GetSystemService(Context.InputMethodService);
313             imm.HideSoftInputFromWindow(edtTxtUrl.WindowToken, 0);
314         }
315 
316         private void CreateSelfApplicationFolder()
317         {
318             selfApplicationDirPath = $"{externalStorageDirPath}{File.Separator}{selfFolderName}";
319             File dir = new File(selfApplicationDirPath);
320             if (!dir.Exists())
321             {
322                 bool retBool = dir.Mkdir();
323             }
324         }
325 
326         private String GetRealPathFromURI(Context context, Android.Net.Uri uri)
327         {
328             String retPath = null;
329             if (context == null || uri == null) return retPath;
330             Boolean isKitKat = Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat;
331             if (isKitKat && DocumentsContract.IsDocumentUri(context, uri))
332             {
333                 if (uri.Authority.Equals("com.android.externalstorage.documents", StringComparison.OrdinalIgnoreCase))
334                 {
335                     String docId = DocumentsContract.GetDocumentId(uri);
336                     String[] split = docId.Split(':');
337                     if (split[0].Equals("primary", StringComparison.OrdinalIgnoreCase))
338                     {
339                         retPath = Android.OS.Environment.ExternalStorageDirectory + "/" + split[1];
340                     }
341                 }
342             }
343             return retPath;
344         }
345 
346         private String GetFilePathFromContentUri(Context context,Android.Net.Uri url)
347         {
348             String filePath = null;
349             String[] filePathColumn = { MediaStore.MediaColumns.Data };
350             using (ICursor cursor = context.ContentResolver.Query(url, filePathColumn, null, null, null))
351             {
352                 if (cursor != null && cursor.MoveToFirst())
353                 {
354                     int columnIndex = cursor.GetColumnIndexOrThrow(filePathColumn[0]);
355                     if (columnIndex > -1)
356                     {
357                         filePath = cursor.GetString(columnIndex);
358                     }
359                 }
360             }
361             return filePath;
362         }
363     }
364 
365     public class MyWebViewClient : WebViewClient
366     {
367         public event MyWebViewPageFinishedDelegate GetWebViewPageFinishedDelegate;
368         public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
369         {
370             view.LoadUrl(request.Url.ToString());
371             return true;
372         }
373 
374         public override void OnPageFinished(WebView view, string url)
375         {
376             base.OnPageFinished(view, url);
377             GetWebViewPageFinishedDelegate();
378         }
379     }
380 
381     public class MyWebChromeClient : WebChromeClient
382     {
383         public event MyWebViewTitleDelegate GetWebViewTitleDelegate;//聲明一個事件
384 
385         public event MyWebViewProgressChangedDelegate GetWebViewProgressChangedDelegate;
386         public override void OnReceivedTitle(WebView view, string title)
387         {
388             base.OnReceivedTitle(view, title);
389             GetWebViewTitleDelegate(title);
390         }
391 
392         public override void OnProgressChanged(WebView view, int newProgress)
393         {
394             base.OnProgressChanged(view, newProgress);
395             GetWebViewProgressChangedDelegate(newProgress);
396         }
397     }
398 }
View Code

  布局代碼:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ProgressBar
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="3dip"
            android:max="100"
            android:progress="0"
            android:visibility="gone"
            android:id="@+id/myBrowserPBar" />
        <android.webkit.WebView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:id="@+id/myBrowser" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/edtTxtUrl"
                android:inputType="text"
                android:singleLine="true"
                android:imeOptions="actionGo"
                android:hint="請輸入網址" />
        </LinearLayout>
    </LinearLayout>
    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="18dp"
        android:visibility="gone"
        android:rotation="90"
        android:src="@drawable/qrcodeScan"
        app:fabSize="mini"
        android:id="@+id/fabSubQRcodeScan" />
    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="18dp"
        android:visibility="gone"
        android:rotation="90"
        android:src="@drawable/saveMht"
        app:fabSize="mini"
        android:id="@+id/fabSubSaveMHT" />
    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="18dp"
        android:visibility="gone"
        android:rotation="90"
        app:fabSize="mini"
        android:id="@+id/fabSubToggleFullScreen" />
    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="10dp"
        android:src="@drawable/plus"
        app:fabSize="normal"
        android:id="@+id/fabMain" />
</RelativeLayout>
View Code

  用到的一些權限

<uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.BIND_INPUT_METHOD" />
View Code

  到此就結束了,webview在8.0下打開content://文件失敗的問題,如果有大神看到,希望幫忙解答,十分感謝!以后有機會在慢慢完善他的功能。

  【2018-06-26更新】

  昨天在小米note3測試本應用,本來是想測試一下看看能不能打開離線文件的問題,但是連關聯MHT都不行,打開的時候,應用列表沒有該應用……郁悶了,越淌水越深啊!

  【2018-11-08更新】

  開始因為版本兼容的問題,掃描二維碼未處理,一直想着過后看看官方能不能解決,但是今天看看,還是不行……但是VS給出了解決方案:

  VS會依次提示單獨安裝上述的幾個包,開始這個項目只安裝了一個包,現在的依賴如下:

  這次添加的相機權限

<uses-permission android:name="android.permission.CAMERA" />

  相機相關代碼

  1、初始化

        protected override void OnCreate(Bundle savedInstanceState)
        {
            ………………
            ………………
            //  5、初始化
            MobileBarcodeScanner.Initialize(Application);
        }

  2、點擊掃描二維碼執行的代碼

        private void FabSubQRcodeScan_Click(object sender, EventArgs e)
        {
            //Toast.MakeText(this, "掃描二維碼", ToastLength.Long).Show();
            Task.Run(() =>
            {
                var scanner = new MobileBarcodeScanner();
                var result = scanner.Scan();
                if (result != null)
                {
                    string scanResult = result.Result.Text;
                    this.RunOnUiThread(new Java.Lang.Runnable(() =>
                    {
                        edtTxtUrl.Text = scanResult;
                        LoadOnePage(scanResult);
                    }));
                }
            });
        }

  經過這次更新,就可以掃描二維碼了……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM