最近做了一个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 ///19 /// 获取网页Title 20 /// 21 /// 22 public delegate void MyWebViewTitleDelegate(string title); 23 24 /// 25 /// 获取网页加载进度 26 /// 27 public delegate void MyWebViewProgressChangedDelegate(int newProgress); 28 29 /// 30 /// 网页加载完成事件 31 /// 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 (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 (Resource.Id.edtTxtUrl); 90 edtTxtUrl.EditorAction += EdtTxtUrl_EditorAction; 91 myBrowserPBar = FindViewById (Resource.Id.myBrowserPBar); 92 93 // 2、右下方悬浮控件 94 fabMain = FindViewById (Resource.Id.fabMain); 95 fabSubQRcodeScan = FindViewById (Resource.Id.fabSubQRcodeScan); 96 fabSubToggleFullScreen = FindViewById (Resource.Id.fabSubToggleFullScreen); 97 fabSubSaveMHT = FindViewById (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
参与评论
手机查看
返回顶部