> 技术文档 > 【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview

【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview


文章目录

  • 简介
  • 依赖
  • 步骤
    • AS(Andriod Studio)创建项目
    • AS创建虚拟机
    • TRAE CN 修改项目
      • 新增按键捕获功能
    • 新增WebView
    • WebView加载本地资源
      • 在按键回调中向WebView注入JS代码
  • 最终关键代码
  • 吐槽

简介

使用Trae配合Andriod Studio开发一个内嵌WebView的安卓应用, 在WebView中加载本地资源, 在APP中捕获按键事件对WebView中的内容进行操作;

依赖

  • Trae CN (https://www.trae.com.cn/)
  • Andriod Studio (https://developer.android.google.cn/studio?hl=zh-cn), 以下简称AS
    • 吃内存, 占用了我大约6GB内存
    • 下载项目依赖和安卓虚拟机(约2GB)依赖网络
  • 基础的编程知识

步骤

AS(Andriod Studio)创建项目

  • 打开AS, 创建一个Empty Activity
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 在AS打开新窗口后, 等待右下角进度条初始化完毕(下载依赖和编译)

AS创建虚拟机

  • 在右上角创建虚拟机
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 找到镜像, 如果是灰色的, 需要点击下载图标进入下载界面(大约2G, 非常依赖网络)
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 启动模板项目
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview

TRAE CN 修改项目

  • 使用Trae打开该文件夹
  • 按下Ctrl+P, 在顶部打开的输入框中输入Main, 选择MainActivity.kt
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 按下Ctrl+U开启右侧AI工具

新增按键捕获功能

  • 输入提示\"我想要安卓应用可以捕获键盘的上下2个方向键并打印日志信息\"

    • 生成完毕后, 在提示框的上方选择\"全部接受\"
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 打开AS, 会自动刷新代码, 点击右上角的绿色重启按钮或者启动按钮重新编译和启动
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview

  • 切换到日志查看界面
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview

  • 鼠标点击模拟器中的应用的白色区域, 后按下上下键, 可看到日志输出

新增WebView

  • 输入提示\"我想将Greeting中的Text控件替换为Webview\"
    • 生成完毕后, 选择\"全部接受\"
  • 这里有个报错信息, 把鼠标移动到红色的文字上会给出提示, 点击import修复一下
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 回到AS, 点击右上角的绿色重启按钮或者启动按钮重新编译和启动
  • 出现了网络连接的错误
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 回到TRAE, 输入提示信息界面提示\"webpage not avalible\"
    • 在点击\"全部接受\"前, 我看了修复内容, 它没添加网络权限还把地址改成google了, 这个方案是不行的, 所以点击\"全部拒绝\"
  • 重新输入提示\"应该是没有配置网络权限, 修复一下\"
    • 它给\"AndroidManifest.xml\"的文件内容清空了, 添加了一行权限代码, 这个方案是不行的, 所以点击\"全部拒绝\"
  • 重新输入提示\"应该是没有配置网络权限, 添加一下相关的权限, 注意不要影响原有的配置信息\"
    • 这次正确的添加了权限, 选择接受
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 回到AS重启项目, 结果提示xml有问题, 仔细一看, 它代码加错位置了, 手动调整一下, 向下挪动一行
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 还是无法打开页面
  • 回到TRAE输入提示信息\"还是提示\"webpage not avalible\", 是不是还缺少哪个网络权限\", 给出新的修复
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 重启后还是不能打开页面, 重启一下虚拟机
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 还是不行, 换了百度网址也不行, 打开自带的谷歌浏览器也访问不了网络, 最后是在下拉的通知栏里重新开关wifi后解决(上一步操作没有成功停止虚拟机)
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 此时发现按键事件的捕获失效了
  • 输入提示信息\"按键事件被Webview捕获了导致应用程序的无法捕获上下键了, 修复一下\" (这里我之前尝试过几次提问, 最后发现是Webview优先处理了事件导致的)
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 回到AS, 编译报错了, 把提示信息MainActivity.kt:61:17 Modifier \'override\' is not applicable to \'local function\'发给TRAE
    • 新回复删除了override解决了报错, 但是没有解决按键的问题
  • 重新输入提示\"不行, 按键事件还是没有被APP捕获到\", 生成了新回复
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 重启项目, 成功解决按键问题

WebView加载本地资源

  • 输入提示\"我想打印webview都请求了哪些链接\"
    • 新增了一个shouldInterceptRequest方法, 这里的斜杠是多余的, 导致没能正确打印日志, 手动删除一下
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 输入提示信息\"我想在shouldInterceptRequest中拦截请求, 然后加载本地的资源文件\"
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 输入提示\"本地资源文件需要放在哪个目录, 帮我生成一个示例\"
    • 这里给出了2步, 一个是手动创建本地文件夹和文件, 一个是修改MainActivity.kt(没有自动修改, 可以点击应用按钮)
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 还需要修改一下拦截的地址(下面的日志打印又改回错误的了, 手动修复一下)
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 有2个导入报错, 鼠标移动到红色文字上, 给出了提示信息, 点击import导入一下, 重启项目
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview

在按键回调中向WebView注入JS代码

  • 输入提示信息\"我想在onKeyDown的回调中修改WebView中的显示内容\"
    • 给了一个通过findViewById实现的方法, 接受后发现不能用, 退回一下
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 输入提示信息\"我想在onKeyDown的回调中修改Greeting中创建的WebView中的显示内容\"
    • 这次他给WebView加了个全局变量webViewInstance, 但是修改后的代码少了花括号, 手动修复一下
  • 发现没效果, 手动加了日志打印了一下日志发现webViewInstance是空的
  • 输入提示信息\"webViewInstance是null, 是不是哪里有问题, 导致没赋值成功\"
    • 只是加了日志, 没解决
  • 输入提示信息\"Greeting 中返回 webView 的时候, webView 还没初始化吧?\"
    • 发癫了, 胡乱输出
  • 输入提示信息\"AndroidView 中是不是异步执行的, 导致返回的webview是null\"
    • 偷懒了, 不想解决问题, 一味的加日志
  • 输入提示信息\"已打印日志确认Greeting中返回的webView是null\"
    • 还是加日志
      【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 输入提示信息\"通过日志发现WebViewReturn提示webView有值, WebViewRequests处为null, 且WebViewRequests 先WebViewReturn输出, 可以确定AndroidView异步执行导致的返回null, 修复一下\"
    • 这次改成了回调的方式, 成功解决
  • 输入提示信息\"不要跳转到new-url, 而是执行JS代码\"
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 手动修改一下
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 没注意看, 重新输入提示\"不要使用webViewInstance?.loadUrl, 使用注入JS的方式\"
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 发现没效果, 打开Edge, 访问\"edge://inspect/#devices\", chrome不行, 会超时然后显示404
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 在控制台直接粘贴JS, 发现js没有问题
  • 输入提示信息\"evaluateJavascript 没有效果\", 给出新修复
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview
  • 重启, 按下上键, 成功解决
    【笔记】Trae+Andrioid Studio+Kotlin开发安卓WebView应用_android studio webview

最终关键代码

  • MainActivity.kt
package com.example.dm2import android.os.Bundleimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.compose.foundation.layout.fillMaxSizeimport androidx.compose.material3.MaterialThemeimport androidx.compose.material3.Surfaceimport androidx.compose.material3.Textimport androidx.compose.runtime.Composableimport androidx.compose.ui.Modifierimport androidx.compose.ui.tooling.preview.Previewimport com.example.dm2.ui.theme.DM2Themeimport android.util.Logimport android.view.KeyEventimport android.webkit.WebViewimport android.webkit.WebViewClientimport android.webkit.WebResourceRequestimport android.webkit.WebResourceResponseimport androidx.compose.ui.platform.LocalContextimport androidx.compose.ui.viewinterop.AndroidViewimport java.io.IOExceptionvar webViewInstance: WebView? = nullclass MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { DM2Theme { Surface(  modifier = Modifier.fillMaxSize(),  color = MaterialTheme.colorScheme.background ) {  Greeting(\"Android\") { webView -> webViewInstance = webView  } } } } } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { KeyEvent.KEYCODE_DPAD_UP -> { Log.d(\"KeyEvent\", \"上方向键被按下\" + webViewInstance) webViewInstance?.evaluateJavascript(\"document.body.innerText = new Date();\", null) return true } } return super.onKeyDown(keyCode, event) }}@Composablefun Greeting(name: String, modifier: Modifier = Modifier, onWebViewCreated: (WebView) -> Unit = {}) { val context = LocalContext.current AndroidView( factory = { ctx -> val webView = WebView(ctx).apply { settings.javaScriptEnabled = true Log.d(\"WebViewInit\", \"WebView实例已创建: $this\") webViewClient = object : WebViewClient() {  override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): android.webkit.WebResourceResponse? { val url = request.url.toString() if (url.equals(\"https://www.example.com/\")) { try { val inputStream = context.assets.open(\"example.html\") return WebResourceResponse(\"text/html\", \"UTF-8\", inputStream) } catch (e: IOException) { e.printStackTrace() } } Log.d(\"WebViewRequests\", \"请求链接: ${request.url}\") return super.shouldInterceptRequest(view, request)  } } loadUrl(\"https://www.example.com\") isFocusable = false isFocusableInTouchMode = false fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {  return false } } onWebViewCreated(webView) return@AndroidView webView }, modifier = modifier )}@Preview(showBackground = true)@Composablefun GreetingPreview() { DM2Theme { Greeting(\"Android\") }}
  • AndroidManifest.xml
<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:tools=\"http://schemas.android.com/tools\"> <uses-permission android:name=\"android.permission.INTERNET\" /> <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" /> <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" /> <application android:allowBackup=\"true\" android:dataExtractionRules=\"@xml/data_extraction_rules\" android:fullBackupContent=\"@xml/backup_rules\" android:icon=\"@mipmap/ic_launcher\" android:label=\"@string/app_name\" android:roundIcon=\"@mipmap/ic_launcher_round\" android:supportsRtl=\"true\" android:theme=\"@style/Theme.DM2\" tools:targetApi=\"31\"> <activity android:name=\".MainActivity\" android:exported=\"true\" android:label=\"@string/app_name\" android:theme=\"@style/Theme.DM2\"> <intent-filter> <action android:name=\"android.intent.action.MAIN\" /> <category android:name=\"android.intent.category.LAUNCHER\" /> </intent-filter> </activity> </application></manifest>
  • example.html
<!DOCTYPE html><html lang=\"zh-CN\"><head> <meta charset=\"UTF-8\"> <title>示例页面</title></head><body> <h1>这是一个本地资源文件示例</h1> <p>该文件从 Android 的 assets 目录加载。</p></body></html>

吐槽

  • java是大家闺秀, js是小伙子, kotlin简直是耍**, 那语法糖看的我抓耳挠腮