AI开发安卓app
前言
鉴于上一篇写的文章,这里就来试试开发一个 app。
由于本人多年未写代码,技术已经严重退化。这里就借助 AI 来进行开发。
连接 Gemini
由于本人电脑上此前已经安装了 Android Studio,相关配置之类的全部跳过。
使用 Gemini 需要从 Android Studio 上面登录 Google 账号,但是 Android Studio 不走系统代理,好几次尝试登录失败。
查阅相关技术文章后找到了解决办法:
开启 Clash 之后,去系统设置界面里找代理服务器设置,然后抄到 AS 的代理设置里。


之后再登录 Google 账号之后,就能使用 Gemini 了。
不过,还要考虑一下 Gemini 的可用区域或国家(比如目前香港并不在可用地区)。
之后通过一些协议,以及配置 Gemini 可访问的项目范围,就可以继续使用了。

搭建框架
由于现在的 AS 变化太大了,加上自己很久不写代码。看着 activity_main.xml 和 MainActivity.kt 两个文件自己都发懵。所以先问问 Deepseek 这是什么。
(提问:我是一个Android开发新手,正在使用Android Studio(版本2024.3.1)进行开发,我发现文件里包括activity_main.xml和MainActivity.kt两个文件。它们有什么用?为什么要采用这种文件结构?)
在 Android 开发中,activity_main.xml 和 MainActivity.kt 这两个文件是典型的 「界面与逻辑分离」 设计思想的体现。它们的角色和分工如下:
一、文件分工
-
activity_main.xml(布局文件)- 作用:定义用户界面(UI),使用 XML 格式描述屏幕上的元素(按钮、文本框、图片等)。
- 特点:
- 纯静态布局,不包含程序逻辑。
- 支持 Android Studio 的 可视化设计工具(Design 视图),可直接拖拽控件。
- 通过
android:id="@+id/myButton"为控件赋予唯一标识符,供代码中引用。
-
MainActivity.kt(逻辑文件)- 作用:处理业务逻辑(例如按钮点击事件、数据计算、网络请求等)。
- 特点:
- 使用 Kotlin(或 Java)编写,动态控制界面行为。
- 通过
setContentView(R.layout.activity_main)绑定对应的 XML 布局。 - 用
findViewById<Button>(R.id.myButton)获取 XML 中的控件实例,并操作它们。
二、为何采用这种结构?
-
关注点分离(Separation of Concerns)
- UI 与逻辑解耦:修改界面时无需改动代码(例如调整按钮颜色),反之亦然(例如修改点击事件逻辑)。
- 降低复杂度:避免将布局和代码混在一起,提高可读性。
-
Android 框架的设计哲学
- Activity 作为控制器:遵循 MVC/MVVM 模式,
MainActivity充当控制器,协调视图(XML)和数据。 - 资源与代码分离:XML 文件存放在
res/layout目录,编译时会被高效处理,支持多设备适配(如不同屏幕尺寸)。
- Activity 作为控制器:遵循 MVC/MVVM 模式,
-
开发工具优化
- 实时预览:Android Studio 可在不运行 App 的情况下预览 XML 布局。
- 代码提示与验证:XML 和 Kotlin 文件分开后,IDE 能提供更精准的错误检查和自动补全。
三、实际协作示例
假设你在 XML 中定义了一个按钮:
1 | <!-- activity_main.xml --> |
在 MainActivity.kt 中处理点击事件:
1 | class MainActivity : AppCompatActivity() { |
四、进阶建议
-
学习数据绑定(Data Binding):进一步简化 XML 和代码的交互,避免繁琐的
findViewById。 -
探索其他架构模式:如 MVVM(配合 ViewModel 和 LiveData)提升代码的可测试性和健壮性。
这种分离结构是 Android 开发的基石,掌握它能让你更高效地构建和维护应用! 🚀
非常通俗易懂,Deepseek 深度思考的过程中考虑到我是个新手,列举都十分浅显易懂,最后还给出了学习建议。
回到 AS,通过 xml 编辑器的 Design 视图,把 EditText 和 Button 两个控件直接拖进来。

架子搭好了,接下来问问 Gemini:

很好,它能理解中文,这我就放心了。
(提问:现在,在界面有一个EditText和一个Button。 我希望点击Button之后, 将EditText的内容作为网址, 用WebView打开。 )
好的,我明白了你的需求。你希望在点击按钮后, 将 EditText 中的文本内容作为网址,然后在 WebView 中打开这个网址。这需要你在布局文件中添加一个 WebView 控件,并在代码中实现相应的逻辑。
以下是如何实现这个功能的步骤和示例代码:
-
在 activity_main.xml 中添加 WebView
首先,在你的布局文件 activity_main.xml 中,添加一个 WebView 控件。你可以将它放在 EditText 和 Button 下方。例如:
1 |
|
-
在 MainActivity.kt 中编写逻辑
在你的 MainActivity.kt 文件中,你需要:
-
获取 EditText、Button 和 WebView 的引用。
-
设置 Button 的点击监听器。
-
在点击事件中,获取 EditText 的文本内容,并加载到 WebView 中。
-
对WebView进行设置,让它能够正常运行。
以下是 MainActivity.kt 的示例代码:
1 | package com.example.myapplication |
代码解释:
-
webView.settings.javaScriptEnabled = true: 这一行代码启用了 WebView 的 JavaScript 功能。如果你的网页需要 JavaScript 才能正常显示,那么这行代码是必须的。否则, 可以省略。 -
webView.webViewClient = WebViewClient(): 这一行代码设置了一个 WebViewClient。通过设置这个,你就可以在你的 WebView 中加载网页,而不是在系统浏览器中打开。 -
button.setOnClickListener: 这是 Button 的点击监听器。当按钮被点击时,里面的代码会被执行。 -
editText.text.toString(): 获取 EditText 中的文本内容,并将其转换为字符串。 -
if (url.startsWith("http://") || url.startsWith("https://")): 检查用户输入的网址是否以 http:// 或 https:// 开头。如果不是,则默认添加 http:// 前缀,因为WebView无法直接处理没有协议前缀的网址。 -
webView.loadUrl(fullUrl): 将处理过的网址加载到 WebView 中。
总结
通过以上步骤,你就完成了在点击按钮后,将 EditText 的内容作为网址在 WebView 中打开的功能。记住,你需要在 AndroidManifest.xml 文件中添加网络访问权限(如果还没有的话) 。 例如:
1 | <uses-permission android:name="android.permission.INTERNET" /> |
希望这个解答能够帮到你!如果你有任何其他问题, 请随时告诉我。
(参考链接略)
(Gemini 的回答复制出来后会丢失排版,上面的回答是我自己重新排版的)
Gemini 给出的解答非常详细,而且它不是在在源代码上改动,而是告诉我解决办法,可以自己复制代码进去。
把代码复制进去运行了一下。
(因为忘了截图,这里只能口头描述了)
界面下方 1/4 的位置变为了 WebView,在文本框里输入网址,点击按钮提交以后,在下面显示出来。
但是测试几下就发现存在问题:默认以 http 打开,但是现在网址大部分网站都是 https 了。
这次我尝试交给 Deepseek 来处理:
要强制 WebView 只加载 HTTPS 网址,可以在 WebViewClient 的 shouldOverrideUrlLoading 方法中检查 URL 的协议,如果不是 HTTPS,则阻止加载或重定向到 HTTPS 版本。以下是相关代码:
强制 WebView 只加载 HTTPS 的代码
1 | webView.setWebViewClient(new WebViewClient() { |
代码说明
-
shouldOverrideUrlLoading:- 检查 URL 是否以
https://开头。 - 如果不是 HTTPS,可以阻止加载或重定向到 HTTPS 版本。
- 检查 URL 是否以
-
onReceivedSslError:- 处理 SSL 错误(例如证书无效)。
- 如果需要强制 HTTPS,可以选择忽略错误继续加载(
handler.proceed()),或者取消加载(handler.cancel())。
注意事项
-
如果目标网站不支持 HTTPS,重定向到 HTTPS 可能会导致页面无法加载。
-
忽略 SSL 错误可能存在安全风险,建议仅在受信任的环境中使用。
通过以上代码,可以强制 WebView 只加载 HTTPS 网址。
我发现自己表述有点问题,重新修正了一下:
以下是修改后的 Kotlin 代码,实现 优先 HTTPS 的功能:
优先 HTTPS 的 Kotlin 代码
1 | webView.webViewClient = object : WebViewClient() { |
代码说明
-
优先 HTTPS:
- 如果 URL 是
http://,尝试将其替换为https://并加载。 - 如果替换后的 HTTPS URL 可用,则加载 HTTPS 版本;否则,继续加载原始 HTTP URL。
- 如果 URL 是
-
shouldOverrideUrlLoading:- 检查 URL 是否以
http://开头。 - 如果是 HTTP,尝试替换为 HTTPS 并加载。
- 检查 URL 是否以
-
onReceivedSslError:- 处理 SSL 错误(例如证书无效)。
- 如果需要优先 HTTPS,可以选择忽略错误继续加载(
handler.proceed()),或者取消加载(handler.cancel())。
注意事项
-
如果目标网站不支持 HTTPS,替换为 HTTPS 后可能会导致页面无法加载。
-
忽略 SSL 错误可能存在安全风险,建议仅在受信任的环境中使用。
通过以上代码,WebView 会优先加载 HTTPS 版本的 URL,同时保留对 HTTP 的支持。
我试着把代码复制回去,但是并没有起作用,于是我又再问 Gemini。
(提问:我希望提交的网址优先以https加载(无论提交的网址有没有http开头) , 且忽略ssl证书错误。 )
好的,我明白了你的需求。你希望即使输入的网址没有 https:// 开头,也优先尝试以 https:// 加载,并且希望 WebView 能够忽略 SSL 证书错误。这意味着你需要修改之前提供的代码, 以实现以下两个目标:
-
优先使用 HTTPS 加载: 即使输入的网址以 http:// 开头,或者根本没有协议头,都要尝试用 https:// 加载。
-
忽略 SSL 证书错误: 在遇到 SSL 证书错误时,允许 WebView 继续加载页面。
以下是修改后的 MainActivity.kt 代码,实现了你的需求:
1 | package com.example.myapplication |
代码解释和修改说明:
-
shouldOverrideUrlLoading 方法的修改:
- 我们重写了
WebViewClient的shouldOverrideUrlLoading方法。 - 在这个方法里,首先获取即将加载的 URL。
- 使用
if (url.startsWith("http://"))判断其是否以http开头。 - 如果以"http://“开头,使用
url.replace("http://", "https://")将其替换为"https://”。 - 使用
view.loadUrl(httpsUrl)尝试加载https的地址。 - 返回true,表示我们已经处理了该URL。
- 如果不是以"http://"开头,使用return false返回false,允许系统按默认逻辑继续加载URL(如正常的https) 。
- 我们重写了
-
onReceivedSslError 方法的修改:
- 我们重写了
WebViewClient的onReceivedSslError方法。 - 在这个方法里,通过调用
handler.proceed()来告诉 WebView 忽略 SSL 证书错误,并继续加载页面。 - 如果你希望取消加载并提示用户,可以调用
handler.cancel()。
- 我们重写了
-
button.setOnClickListener 内的修改:
- 使用
if (url.startsWith("http://"))判断其是否以http开头,如果是,直接使用url.replace("http://","https://")来替换成https开头。 - 使用
else if (url.startsWith("https://"))判断其是否以https开头,如果是,则直接使用该URL。 - 使用else来处理不以"http://“和"https: / / " 开头的网址, 直接在其前面添加” https: / / " 。
- 统一使用
webView.loadUrl(fullUrl)进行加载。
- 使用
总结:
通过这些修改,无论用户在 EditText 中输入的是 http:// 开头的网址,https:// 开头的网址,还是没有协议头的网址,WebView 都会优先尝试使用 https:// 进行加载。并且,在遇到 SSL 证书错误时,WebView 将会忽略错误并继续加载页面。
请注意,忽略 SSL 证书错误可能会带来安全风险,请根据你的应用场景谨慎使用。 在某些情况下, 你可能需要考虑提示用户存在安全风险, 或者完全拒绝加载存在 SSL 证书错误的页面。
希望这个修改后的代码能够完美地满足你的需求! 如果你还有其他问题, 请随时告诉我。
(参考链接略)
实际阅读后发现,Gemini 其实只改了 button.setOnClickListener,因为我在和 Deepseek 讲的时候,Deepseek 并不知道有一个按钮监听事件。所以代码没有起作用。
而且我之前也没有仔细读代码,没注意到之前写的 if (url.startsWith("http://") || url.startsWith("https://")) 这个判定。
不过从结果上来说,至少是把最基本的功能实现了。
独立 WebView
接下来我打算把 WebView 放到单独的 Activity 里面,这样子既符合操作逻辑也方便对 WebView 单独处理。
不过稳妥起见,我还是先问问 Deepseek。
(提问:如何理解Android中的activity?是否应该把一个webview放进一个activity里面?)
如何理解 Android 中的 Activity?
Activity 是 Android 应用的基本组件之一,代表一个单独的屏幕或用户界面。每个 Activity 都负责管理一个窗口(Window),用户可以在其中与应用交互。以下是 Activity 的核心特点:
-
生命周期:
- Activity 有自己的生命周期方法(如
onCreate()、onStart()、onResume()、onPause()、onStop()、onDestroy()),用于管理其创建、启动、暂停、停止和销毁的过程。
- Activity 有自己的生命周期方法(如
-
用户界面:
- Activity 通常通过
setContentView()方法加载一个布局文件(XML),用于显示用户界面。
- Activity 通常通过
-
任务和返回栈:
- Activity 是任务(Task)的基本单元,任务是一组按顺序排列的 Activity,用户可以通过返回按钮在它们之间导航。
-
通信:
- Activity 可以通过
Intent与其他 Activity 或组件通信,传递数据或启动新的界面。
- Activity 可以通过
-
独立性:
- 每个 Activity 是独立的,可以单独运行或与其他 Activity 组合使用。
是否应该把一个 WebView 放进一个 Activity 里面?
是的,通常应该将 WebView 放在一个 Activity 中。以下是原因和最佳实践:
-
Activity 是管理 UI 的最佳选择
- Activity 是 Android 中管理用户界面的标准组件,适合用于加载和显示 WebView。
- 通过 Activity 的生命周期方法,可以更好地管理 WebView 的状态(如页面加载、资源释放等)。
-
生命周期管理
- WebView 是一个重量级组件,占用较多资源。将其放在 Activity 中可以方便地管理其生命周期:
- 在
onCreate()中初始化 WebView。 - 在
onPause()和onResume()中暂停或恢复 WebView 的渲染和加载。 - 在
onDestroy()中释放 WebView 的资源,避免内存泄漏。
- 在
- WebView 是一个重量级组件,占用较多资源。将其放在 Activity 中可以方便地管理其生命周期:
1 | class WebViewActivity : AppCompatActivity() { |
-
导航和返回栈
- 将 WebView 放在单独的 Activity 中,可以利用 Android 的任务和返回栈机制:
- 用户可以通过返回按钮返回到上一个界面。
- 可以通过
Intent启动 WebViewActivity,并传递 URL 或其他参数。
1
2
3val intent = Intent(this, WebViewActivity::class.java)
intent.putExtra("url", "https://www.example.com")
startActivity(intent) - 将 WebView 放在单独的 Activity 中,可以利用 Android 的任务和返回栈机制:
-
灵活性和可扩展性
- 将 WebView 放在单独的 Activity 中,可以更灵活地扩展功能:
- 添加自定义工具栏(如前进、后退按钮)。
- 处理特定的 URL 协议(如
tel:、mailto:)。 - 支持多窗口模式(如分屏模式)。
- 将 WebView 放在单独的 Activity 中,可以更灵活地扩展功能:
-
性能优化
- 将 WebView 放在单独的 Activity 中,可以更好地控制其资源使用:
- 在不需要时销毁 Activity,释放 WebView 占用的内存。
- 避免在复杂的界面中因 WebView 导致卡顿。
- 将 WebView 放在单独的 Activity 中,可以更好地控制其资源使用:
什么情况下不需要将 WebView 放在单独的 Activity 中?
虽然通常建议将 WebView 放在单独的 Activity 中,但在以下情况下可以考虑将其嵌入到现有界面中:
-
简单的内嵌网页:
- 如果只是显示一个简单的网页(如帮助文档、关于页面),可以直接将 WebView 嵌入到 Fragment 或现有布局中。
-
性能要求不高:
- 如果 WebView 的使用场景不频繁,且对性能要求不高,可以将其嵌入到现有界面中。
-
界面复杂度低:
- 如果界面本身比较简单,且 WebView 不会占用过多资源,可以将其嵌入到现有界面中。
总结
-
Activity 是 Android 中管理用户界面的核心组件,适合用于加载和显示 WebView。
-
将 WebView 放在单独的 Activity 中 是推荐的做法,便于生命周期管理、导航控制和性能优化。
-
在简单场景中,可以将 WebView 嵌入到现有界面中,但需要注意资源管理和性能问题。
好吧,那就直接开工。
经过之前的教训,凡是要直接改代码的地方,我就直接问 Gemini:
(提问:修改button的逻辑,点击button后创建一个新的Activity, 之前的Webview放在这个Activity里面。 通过返回键销毁Webview所在的Activity并返回上一界面。 )
好的,我明白了你的新需求。你现在希望:
-
点击按钮后,启动一个新的 Activity。
-
将 WebView 放到这个新的 Activity 中显示网页。
-
通过按下返回键,销毁 WebView 所在的 Activity,并返回到前一个界面。
要实现这个功能,你需要创建新的 Activity,并修改 Button 的点击事件处理逻辑。以下是具体的步骤和代码:
步骤 1: 创建新的 Activity (WebViewActivity)
首先,你需要创建一个新的 Activity,我们称之为 WebViewActivity,用于显示 WebView。
-
创建布局文件:
- 在 res/layout 目录下,创建一个名为 activity_web_view.xml 的布局文件。
- 在该文件中,添加一个 WebView 控件。
1 |
|
-
创建 WebViewActivity.kt 文件:
- 在你的包目录下,创建一个名为 WebViewActivity.kt 的 Kotlin 文件。
- 在这个文件中,编写 WebViewActivity 的代码。
1 | package com.example.myapplication |
-
在AndroidManifest.xml中注册Activity
1 | <activity |
步骤 2: 修改 MainActivity.kt
修改 MainActivity.kt,使其在点击 Button 时启动 WebViewActivity。
1 | package com.example.myapplication |
代码解释:
-
WebViewActivity.kt:
webView = findViewById(R.id.webView): 获取 WebView 的引用。webView.settings.javaScriptEnabled = true: 启用 JavaScript。webView.webViewClient = object : WebViewClient() { ... }: 设置 WebViewClient,实现shouldOverrideUrlLoading和onReceivedSslError方法,保证优先使用 HTTPS 加载以及忽略证书错误。val url = intent.getStringExtra("url"): 从 Intent 中获取传递过来的 URL。webView.loadUrl(url): 加载 URL。
-
MainActivity.kt:
val intent = Intent(this, WebViewActivity::class.java): 创建一个 Intent,用于启动 WebViewActivity。intent.putExtra("url", fullUrl): 将处理后的 URL 放入 Intent 中,传递给 WebViewActivity。startActivity(intent): 启动 WebViewActivity。
步骤 3: 确保网络权限
确保你的 AndroidManifest.xml 文件中已经声明了网络权限:
1 | <uses-permission android:name="android.permission.INTERNET" /> |
运行应用
现在运行你的应用,点击按钮后,应该会启动一个新的 Activity,并在其中显示 WebView 加载的网页。按下返回键,会销毁 WebViewActivity,返回到 MainActivity。
总结
通过以上步骤,你已经成功实现了以下功能:
-
点击 Button 后,启动新的 WebViewActivity。
-
在 WebViewActivity 中显示 WebView 加载的网页。
-
通过返回键,销毁 WebViewActivity 并返回到 MainActivity。
-
优先使用HTTPS加载,并且忽略ssl错误。
这个方案使用了Intent在两个Activity之间传递数据,且能保证WebView能在新的Activity中显示,希望能帮到你! 如果还有其他问题, 请随时告诉我。
(参考链接略)
看上去给的都非常详细。
我觉得一定没什么问题,满怀信心地点击了运行。
然后,app 闪退了……

赶紧看看 logcat 记录的错误日志

这里非常贴心地在错误旁边加了个 Ask Gemini,直接可以把错误信息发给 Gemini 进行分析。
一番折腾发现是自己没把之前在 MainActivity.kt 里面的代码清理干净…… OTZ
解析地址
接下来就是比较麻烦的部分。
首先,以抖音视频为例,以用户的角度来说,操作步骤如下:
通过 app 的分享功能获取到文本:
1 | 4.66 复制打开抖音,看看【西诺说影的作品】站直啰,别趴下(第一视角) 冯巩主演,一部让人看完... https://v.douyin.com/i5chLVyT/ W@M.jp OKj:/ 09/17 |
提取出短链接:
1 | https://v.douyin.com/i5chLVyT/ |
浏览器的UA使用PC模式,获取到网址:
1 | https://www.douyin.com/video/7479005522700635418 |
通过网址提取到视频ID:
1 | 7479005522700635418 |
将视频 ID 给开放端口:
1 | https://open.douyin.com/player/video?vid=7479005522700635418 |
将网址放进浏览器里打开
把步骤分开拆解,一步步来。
首先,先局限于处理抖音链接。
首先先对EditText的内容进行判定:
提问:
1 | 给我一个正则表达式,能够从以下内容中提取到网址: |
要从给定的内容中提取网址,可以使用以下正则表达式:
1 | https?://[^\s]+ |
解释:
-
https?:匹配http或https。 -
://:匹配://。 -
[^\s]+:匹配一个或多个非空白字符(即网址的剩余部分)。
示例代码(Python):
1 | import re |
输出
1 | 提取到的网址: https://v.douyin.com/i5chLVyT/ |
这个正则表达式能够从文本中提取出完整的网址。
接下来再要求 Gemini 改代码:
提问:
1 | 接下来,我要求实现以下功能: |
好的,我明白了你的需求。你现在希望在点击 Button 提交时,对 EditText 的内容进行以下验证和处理:
-
内容验证: 检查 EditText 中的文本是否包含 “douyin.com”。如果不包含,则显示提示信息 “请输入正确的内容”。
-
网址提取: 使用正则表达式
https?://[^\s]+从 EditText 的文本中提取网址。
为了实现这些功能,你需要修改 MainActivity.kt 中的 Button 点击事件处理逻辑。以下是修改后的代码:
1 | package com.example.myapplication |
代码解释和修改说明:
-
验证是否包含 “douyin.com”:
if (!inputText.contains("douyin.com")):使用contains()方法检查inputText是否包含 “douyin.com”。Toast.makeText(this, "请输入正确的内容", Toast.LENGTH_SHORT).show():如果不包含,显示提示信息 “请输入正确的内容”。return@setOnClickListener:使用此方法来停止执行后续代码,避免错误执行。
-
使用正则表达式提取网址:
val regex = Regex("https?://[^\\s]+"):创建一个 Regex 对象,使用正则表达式 “https?://[^\\s]+”。https?:匹配 “http” 或 “https”。://:匹配 “://”。[^\\s]+:匹配一个或多个非空白字符(即,直到遇到空格为止) 。
val matchResult = regex.find(inputText):使用find()方法在inputText中查找匹配的字符串。if (matchResult != null):检查是否找到匹配项。val extractedUrl = matchResult.value:如果找到匹配项,使用value属性获取匹配的字符串。Toast.makeText(this, "无法提取到有效的网址", Toast.LENGTH_SHORT).show():如果没有找到匹配项,显示提示信息 “无法提取到有效的网址”。
-
启动WebViewActivity:
- 和先前代码逻辑一致。
改进和考虑:
-
错误处理: 你可以根据实际情况,决定如何处理提取不到网址的情况。 例如, 你可以显示一个更详细的错误信息, 或者让用户重新输入。
-
正则表达式的优化: 你可以根据实际需求,对正则表达式进行进一步的优化, 以匹配更复杂的网址结构。
-
测试: 需要使用不同的字符串进行测试,以确保此代码符合你的要求。
总结:
通过以上修改,你的 MainActivity 现在可以:
-
验证 EditText 的内容是否包含 “douyin.com”。
-
使用正则表达式提取其中的网址。
-
如果验证失败,显示 “请输入正确的内容” 的提示信息。
-
如果提取不到网址,显示 “无法提取到有效的网址”。
-
如果以上步骤都成功,将提取到的网址传递给 WebViewActivity。
希望这个修改后的代码能够完全满足你的需求! 如果你还有任何其他问题, 请随时告诉我。
(参考链接略)
到这里,判定功能实现了。
先写到这里,之后再研究。