当前位置: 首页 > news >正文

零基础学 ArkUI24:手把手教你开发一个简易浏览器 App

🌐 零基础学 ArkUI24:手把手教你开发一个简易浏览器 App

博主说:手机浏览器是我们每天打开最多次的应用之一。你有没有想过——在 HarmonyOS 上实现一个简易浏览器其实只需要几十行代码?ArkUI 内置了强大的Web 组件,可以轻松加载网页、执行 JavaScript、处理页面加载事件。今天我们就用 Web 组件做一款支持导航栏、前进后退、加载进度、书签管理的简易浏览器


📱 应用场景

在 App 内嵌网页查看内容、快速访问常用网站、开发 Hybrid 应用时调试前端页面……简易浏览器的应用场景非常广泛。我们要开发的浏览器会实现:

  • 地址栏输入 URL 并加载
  • 加载进度条
  • 前进 / 后退 / 刷新
  • 网页标题显示
  • 书签管理(收藏常用网站)
  • 加载状态提示(加载中 / 加载失败)
  • 全屏模式(扩展)

⚙️ 运行环境要求

项目版本要求
操作系统Windows 10/11、macOS 13+ 或 Ubuntu 22.04+
DevEco Studio5.0.3.800 及以上
HarmonyOS SDKAPI 12(HarmonyOS 5.0.0)及以上
应用模型Stage 模型
开发语言ArkTS
核心组件Web@ohos.web.webview

🛠️ 实战:从零搭建简易浏览器

Step 1:认识 ArkUI 的 Web 组件

Web组件是 ArkUI 内置的网页渲染引擎,基于 Chromium 内核:

importwebviewfrom'@ohos.web.webview';// 在 build 中使用 Web 组件Web({src:'https://www.example.com',controller:this.controller}).width('100%').height('100%').javaScriptAccess(true)// 允许 JS.domStorageAccess(true)// 允许 DOM 存储.onPageBegin((url)=>{/* 开始加载 */}).onPageEnd((url)=>{/* 加载完成 */}).onErrorReceive((err)=>{/* 加载出错 */})

Step 2:浏览器数据结构设计

// 书签数据结构interfaceBookmark{id:string;title:string;url:string;icon:string;// favicon}// WebView 控制器controller:webview.WebviewController=newwebview.WebviewController();// 浏览历史(用于前进/后退判断)@StatecanGoBack:boolean=false;@StatecanGoForward:boolean=false;

Step 3:完整代码

// pages/Index.ets — 简易浏览器主页面importwebviewfrom'@ohos.web.webview';interfaceBookmark{id:string;title:string;url:string;}@Entry@Componentstruct SimpleBrowser{// ======== 状态变量 ========@StateurlInput:string='https://www.example.com';@StatepageTitle:string='';@StateisLoading:boolean=false;@StateloadProgress:number=0;@StatecanGoBack:boolean=false;@StatecanGoForward:boolean=false;@StateshowBookmarks:boolean=false;@Statebookmarks:Bookmark[]=[{id:'1',title:'HarmonyOS 开发文档',url:'https://developer.harmonyos.com'},{id:'2',title:'华为开发者社区',url:'https://developer.huawei.com'},{id:'3',title:'CSDN',url:'https://www.csdn.net'},];privatecontroller:webview.WebviewController=newwebview.WebviewController();privatewebviewRef:string='webview';// ======== 页面生命周期 ========aboutToAppear(){// 默认加载首页this.loadUrl(this.urlInput);}// ======== 加载 URL ========loadUrl(url:string){if(!url.startsWith('http://')&&!url.startsWith('https://')){url='https://'+url;}this.urlInput=url;this.isLoading=true;this.loadProgress=0;this.controller.loadUrl(url);}// ======== 导航控制 ========goBack(){if(this.controller.accessBackward()){this.controller.backward();}}goForward(){if(this.controller.accessForward()){this.controller.forward();}}refresh(){this.controller.refresh();}// ======== 添加书签 ========addBookmark(){constnewBookmark:Bookmark={id:Date.now().toString(),title:this.pageTitle||this.urlInput,url:this.urlInput};// 去重constexists=this.bookmarks.find(b=>b.url===newBookmark.url);if(!exists){this.bookmarks.push(newBookmark);}}// ======== 删除书签 ========deleteBookmark(bm:Bookmark){constidx=this.bookmarks.indexOf(bm);if(idx>-1)this.bookmarks.splice(idx,1);}// ======== UI 构建 ========build(){Column(){// ---- 地址栏 + 导航按钮 ----Row(){Button('<').fontSize(20).backgroundColor('transparent').fontColor(this.canGoBack?'#007AFF':'#ccc').enabled(this.canGoBack).onClick(()=>{this.goBack();})Button('>').fontSize(20).backgroundColor('transparent').fontColor(this.canGoForward?'#007AFF':'#ccc').enabled(this.canGoForward).onClick(()=>{this.goForward();})TextInput({placeholder:'输入网址...',text:this.urlInput}).layoutWeight(1).height(36).backgroundColor('#F0F0F0').borderRadius(18).padding({left:12}).onSubmit((val:string)=>{this.loadUrl(val);})Button('↻').fontSize(18).backgroundColor('transparent').fontColor('#007AFF').onClick(()=>{this.refresh();})Button('🔖').fontSize(16).backgroundColor('transparent').onClick(()=>{this.addBookmark();})}.width('100%').padding({top:8,bottom:4,left:8,right:8}).backgroundColor('#F8F8F8')// ---- 加载进度条 ----if(this.isLoading){Progress({value:this.loadProgress,total:100,type:ProgressType.Linear}).width('100%').height(3).color('#007AFF').value(this.loadProgress)}// ---- 书签收藏栏 ----if(this.showBookmarks){Column(){Row(){Text('🔖 书签').fontSize(16).fontWeight(FontWeight.Bold)Button('✕').fontSize(14).backgroundColor('transparent').fontColor('#999').onClick(()=>{this.showBookmarks=false;})}.width('100%').justifyContent(FlexAlign.SpaceBetween)List(){ForEach(this.bookmarks,(bm:Bookmark)=>{ListItem(){Row(){Text('📄').fontSize(20)Column(){Text(bm.title).fontSize(14).fontWeight(FontWeight.Bold)Text(bm.url).fontSize(11).fontColor('#999').textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1)}.layoutWeight(1).margin({left:8})Button('✕').fontSize(12).backgroundColor('transparent').fontColor('#FF3B30').onClick(()=>{this.deleteBookmark(bm);})}.padding(10).width('100%')}.onClick(()=>{this.loadUrl(bm.url);this.showBookmarks=false;})},(bm:Bookmark)=>bm.id)}.height(200)}.width('100%').backgroundColor('#fff').shadow({radius:4,color:'#20000000',offsetY:2})}// ---- 网页内容区域 ----Web({src:this.urlInput,controller:this.controller}).width('100%').layoutWeight(1).javaScriptAccess(true).domStorageAccess(true).onPageBegin(()=>{this.isLoading=true;this.loadProgress=0;}).onPageEnd((event)=>{this.isLoading=false;this.loadProgress=100;this.pageTitle=this.controller.title();// 更新前进/后退状态this.canGoBack=this.controller.accessBackward();this.canGoForward=this.controller.accessForward();}).onProgressChange((event)=>{this.loadProgress=event.newProgress;}).onErrorReceive((event)=>{this.isLoading=false;console.error('页面加载失败:',event.request.getRequestUrl());}).onTitleReceive((event)=>{this.pageTitle=event.title;})// ---- 底部状态栏 ----Row(){if(this.isLoading){Text('加载中...').fontSize(12).fontColor('#007AFF')}else{Text(this.pageTitle||this.urlInput).fontSize(12).fontColor('#999').textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(1)}Text('🔖').fontSize(14).onClick(()=>{this.showBookmarks=!this.showBookmarks;})}.width('100%').padding({left:16,right:16,top:6,bottom:6}).backgroundColor('#F0F0F0').justifyContent(FlexAlign.SpaceBetween)}.width('100%').height('100%').backgroundColor('#FFFFFF')}}

📚 核心知识点深度解析

1. Web 组件的核心属性

属性作用示例
javascriptAccess(true)启用 JS 执行网页功能正常
domStorageAccess(true)启用 localStorage记住登录状态
onPageBegin开始加载回调显示加载动画
onPageEnd加载完成回调隐藏加载动画
onProgressChange进度变化回调更新进度条
onErrorReceive加载错误回调错误提示

2. WebviewController 控制方法

controller.loadUrl(url)// 加载 URLcontroller.backward()// 后退controller.forward()// 前进controller.refresh()// 刷新controller.title()// 获取页面标题controller.accessBackward()// 能否后退controller.accessForward()// 能否前进

3. 浏览器状态机

用户输入 URL → loadUrl() → 开始加载(isLoading=true) ↓ onProgressChange → 更新进度条 ↓ onPageEnd → 标题更新 + 前进/后退状态更新 ↓ 加载完成(isLoading=false)

⚠️ 避坑指南

原因正确做法
网页白屏忘了javascriptAccess(true)domStorageAccess(true)必须开启这两个属性
URL 加载失败用户输入了 “baidu.com” 不带协议自动补全https://
前进/后退按钮无效没调用accessBackward()判断页面加载完后更新状态
进度条不更新没监听onProgressChange绑定 onProgressChange 事件
书签数据丢失只存在内存中preferences持久化
页面标题为空页面还没触发 onTitleReceive降级使用 URL 作为标题

🔥 最佳实践

  1. URL 自动补全:用户输入不带http(s)://时自动补全,减少输入错误
  2. 加载进度条:用 Linear Progress 给用户视觉反馈,提升体验
  3. 前进/后退状态灰化:不能前进时按钮用灰色#cccenabled(false)
  4. 书签去重:添加前检查 URL 是否已存在
  5. 错误处理onErrorReceive中显示友好提示而非直接白屏
  6. 地址栏实时显示:单页应用(SPA)URL 变化时,用 JavaScript 桥接更新地址栏

🚀 扩展挑战

  1. 多标签页:支持多个 Web 实例,通过 Tab 切换
  2. 无痕模式:加载时使用incognitoMode(true)
  3. 广告过滤:通过onInterceptRequest拦截广告请求
  4. Javascript 桥接:通过javaScriptProxy()实现 App 与网页双向通信
  5. 下载管理:监听onDownloadStart实现文件下载
  6. 暗黑模式:通过 CSS 注入prefers-color-scheme: dark

运行结果完整截图:


官方文档:HarmonyOS 应用开发文档

  • 开发者社区:华为开发者论坛
  • 欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net/
http://www.jsqmd.com/news/977403/

相关文章:

  • 【倒摆控制】三重倒摆控制项目(采用噪声和卡尔曼滤波技术)附Matlab实现
  • 互关原则
  • 3分钟搞定B站全量评论爬取:零代码获取10万+评论的完整解决方案
  • 一篇读懂薛定谔定律:从微观宇宙到人生启示
  • Midscene.js:AI驱动的跨平台UI自动化革命
  • PrivateGPT 1.0:构建企业级私有AI应用的开源API层
  • 2026推荐:广州双极真空泵维修服务公司专业精修与高效服务之选 - 企业推荐官【官方】
  • Zotero-GPT插件API调用故障排查:3步解决AI功能失效问题
  • 2026年GEO优化服务商可靠性综合评估报告:数据驱动下的专业选型指南 - GEO优化
  • 人力资源数据分析实用指南:HR新人同事必读
  • 【飞机】基于数据驱动的多传感器飞机健康监测系统附Matlab代码
  • LPC845 I2C SBL实战:嵌入式固件远程更新与内存布局解析
  • LLM —— Prompt提示词工程
  • GoLiveChat:Golang独立部署海外英文在线客服系统全解析
  • 【网络实验】用华为eNSP配置路由器DHCP服务,实现PC自动获取IP地址
  • 如何用10分钟语音数据训练专属AI音色:Retrieval-based-Voice-Conversion-WebUI完整指南
  • 屏幕卡死无法点击?只用键盘重启电脑
  • (毕业必看)实测好用的AI写作辅助软件,毕业党收藏备用
  • 《置身钉内》原文-可播放阅读
  • 打破监控协议壁垒:go2rtc如何让传统摄像头在现代浏览器中焕发新生
  • OpenDroneMap:开源无人机摄影测量系统的架构解析与技术实现
  • 终极指南:Ucupaint让Blender纹理图层管理变得如此简单![特殊字符]
  • PN7642 NFC开发板实战:从硬件连接到射频测试全流程指南
  • 2026年 HC600/980QP高强钢厂家推荐榜单:汽车轻量化核心板材与冲压性能深度解析 - 品牌发掘
  • 原神FPS解锁工具:终极免费突破60帧限制完整指南
  • 嵌入式低功耗实战:从Cortex-M0+睡眠模式到KM35Z75 VLLS3微安级功耗实现
  • 如何高效使用BBDown:B站视频下载的终极命令行方案
  • 2026年6月GEO优化公司最推荐哪家?头部主流五家GEO服务商评测与对比横评 - GEO优化
  • HR外包工具横向评测:单租户SaaS真的难解差异化规则?实在Agent以非侵入式AI重构企业数字化转型
  • 2026实力厂商推荐:超越创新LED 球形屏、球幕 LED 显示屏、异型屏、全息沉浸式屏、LED 圆形屏定制供应商深度解 - 栗子测评