Android答题APP源码解析:Java/Kotlin混编与WebView题库加载

📅 发布时间:2026/9/26 13:31:17
Android答题APP源码解析:Java/Kotlin混编与WebView题库加载
简介这是一套以Java与Kotlin联合编写、并借助HTML构建前端界面的综合答题应用源码定位为移动端在线刷题与测验的完整工程适合Android开发者、编程爱好者以及希望快速搭建答题类产品的小团队。资源整体结构清晰共包含786个文件核心类型涵盖界面图片、Java逻辑代码、XML布局与配置、第三方功能库、JSON数据结构、Gradle自动化构建脚本等各类素材与代码分工明确压缩包整体大小约47.87MB。目前已有347人学习下载。读者可以从源码中深入理解两种语言在同一个Android项目中的协作关系学习如何让HTML页面与原生组件互通同时还能参考登录模块、工作区组织方式以及资源文件的分类管理思路便于在此基础上进行二次功能开发也是一份贴近真实项目的移动端实战学习范例。1. 一套能直接答辩的Android答题APPJava、Kotlin与HTML题库是怎么拼在一起的把“基于Java和Kotlin的HTML整合答题APP设计源码”拆开看就是Android原生壳加上WebView题库渲染Java管入口和稳定层Kotlin管业务与数据交互题目本身不写死在Java代码里而是以HTML文件放进assets目录运行时交给WebView展示。对准备课程设计、毕设或者想在面试里把WebView与JSBridge讲清楚的人来说这是性价比很高的一条路——不用从零写界面换题库基本等于替换HTML文件功能点也容易演示。这套源码解决的是“怎么用最少的原生代码做出一套可维护、可换题的答题应用”。2. 先拆源码结构再谈跑通Java与Kotlin混编的模块边界在哪这类源码的工程体积一般不大但语言混编容易让人一打开就懵。常见布局是MainActivity留在Java答题页和数据处理放在KotlinHTML题库整体扔在assets目录。先明白为什么这样分后面跑通和改造才不会乱动错文件。2.1 为什么答题页普遍用HTML承载原生布局的维护成本说不过去答题页看起来简单一问一答配四个选项但真用原生控件写很快会遇到三个麻烦。第一题目内容不可控有些题带代码块、表格、图片甚至音频原生布局每加一种元素就要补一个控件工作量大第二题库更新要重新发版哪怕只改一道题也要重新编译整个APK第三图文混排样式调整极其痛苦用HTML加CSS随手就能改Android的Spannable写复杂排版会写到怀疑人生。用WebView承载HTML以后思路就变了HTML本身就是题库的展示层JS监听用户点击再通过Android提供的JavaScriptInterface把答案回传原生层。这一套组合在真实项目里很常见也是很多Java面试题里会追问的“原生与前端怎么通信”的落地答案。2.2 Java/Kotlin双语言源码的典型分层Activity、Bridge与题库三块混编不是把文件随便混在一起。我拆过不少这类源码结构基本都长这样java目录下是入口Activity负责启动页、权限申请这部分保留Java往往是为了兼容老设备或者作者当时写了一半kotlin目录下是业务层QuizActivity.kt管理WebView生命周期、读取assets、接收JS回调如果涉及JSON解析还会有几个data class定义题目模型。三者各管一摊职责边界很清晰。Java和Kotlin能直接互相调用不是玄学。Kotlin编译后同样生成字节码跑在JVM上Java类里的方法、字段在Kotlin里可以当作普通类用Kotlin的顶层函数编译后会生成带类名的静态方法Java侧也能调。所以你经常看到MainActivity.java直接new一个Kotlin写好的Bridge类或者Kotlin里的WebViewClient匿名对象覆写Java接口方法编译器都能认。注意一个小地方Kotlin的data class如果带默认参数Java调用时不会自动应用默认值必须显式传全参构造器。这类源码里凡是Java和Kotlin交界的数据类我一般会显式写全构造函数而不是依赖JvmOverloads注解这样调用处更直观也少一点联调时的意外。2.3 assets目录约定HTML题库和静态资源的分工凡是叫“HTML整合”的答题应用题库一定在assets下不会放在res里。原因很简单assets里的文件保持原始路径和文件名可以整体读取、按目录管理、运行时动态拼路径而res的raw目录虽然也能放文件但资源名会被编译期约束不适合大量HTML文件维护。常见的文件组织方式assets/html/放题目页一个HTML文件对应一道题或一套题assets/html/css/、assets/html/js/放公共样式和交互脚本assets/html/img/题目里的插图相对路径引用assets/data/如果题目数量多会有一个questions.json做索引记录每个HTML文件的标题、难度和顺序HTML里引用CSS用相对路径比如 hrefcss/main.css relstylesheet/ 这样当WebView以assets为基准目录加载时资源能正常解析。如果用了绝对路径写死硬盘地址一上真机就白屏这条后面进避坑章节再细说。3. 在Android Studio里把源码跑通环境对齐与最小改动拿到源码第一步不是看代码而是把环境对齐。混编项目最常见的跑不起来不是代码坏了而是Gradle插件、Kotlin版本和JDK三者不匹配。先把环境钉死再谈改逻辑。3.1 环境核对清单JDK、Gradle插件、kotlinOptions一次对准打开项目根目录的build.gradle和gradle-wrapper.properties先看三个版本Android Gradle Plugin版本、Gradle版本、Kotlin插件版本。这三个必须匹配否则同步阶段就报错。另外JDK版本也要对AGP 7.x要求JDK 11以上AGP 8.x建议JDK 17Android Studio自带的JBR通常没问题但如果你是单独配了系统JDK务必确认JAVA_HOME指向正确这一步能挡掉一大半环境问题。我一般会把环境参数整理成一张表贴在工作笔记里AGP版本Gradle版本JDK版本对应Android Studio7.27.4.x11Dolphin7.47.511Electric Eel8.18.017Hedgehog确认版本后再看app/build.gradle里的依赖和编译参数。这里有个高频配置如果源码里带了本地aar或jar文件依赖要写成fileTree而不是手写单个文件名。写法如下dependencies { implementation fileTree(dir: libs, include: [*.jar, *.aar]) implementation androidx.appcompat:appcompat:1.6.1 implementation androidx.constraintlayout:constraintlayout:2.1.4 implementation org.jetbrains.kotlin:kotlin-stdlib:1.8.21 implementation com.google.android.material:material:1.9.0 implementation com.google.code.gson:gson:2.10.1 }这段配置里fileTree会把libs目录下所有以.jar和.aar结尾的文件都引入编译不用一个个写文件名。kotlin-stdlib版本必须和根build.gradle里的kotlin插件版本一致否则Kotlin反射库和协程库可能编译不过。material是UI库如果源码里有BottomNavigationView或者ProgressBar的Material样式这行不能删。3.2 导入工程后的包名与签名改动三步换皮环境对齐后项目能同步成功但还不能直接安装到自己手机上。如果直接跑应用ID还是作者的包名签名也是debug默认签名自己玩可以要提交到自己的账号下就得改。第一步改applicationId。在app/build.gradle的defaultConfig里找到applicationId com.xxx.quiz改成你自己的包名比如com.yourname.quiz。注意applicationId不是代码里的package路径但建议两者保持一致减少Kotlin文件里包名混乱带来的麻烦。第二步改AndroidManifest里的package已经不用写了关键是检查 下的权限和Activity声明。答题应用通常需要网络权限如果题库在本地则不需要但外部图片会用到。常见声明如下uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE /第三步改应用的显示名称。在strings.xml里找到app_name字段改成你自己的标题比如“XX题库”。顺手把应用图标换掉否则答辩时两个APP图标一模一样老师一问就露馅。3.3 让题库先跑起来的核心代码WebView加载assets里的HTML环境没问题以后第一个要跑通的功能就是WebView加载assets里的HTML。这个页面是答题APP的主战场代码写法大同小异核心逻辑都在Activity里。下面是一段我在这类源码里经常见到的实现class QuizActivity : AppCompatActivity() { private lateinit var webView: WebView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_quiz) webView findViewById(R.id.webView) initWebView() loadHtmlFromAssets(html/quiz_01.html) } private fun initWebView() { webView.settings.apply { javaScriptEnabled true domStorageEnabled true allowFileAccess true } webView.webViewClient object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { // 只允许加载assets里面的本地页面 return url?.startsWith(file:///android_asset/) ! true } } } private fun loadHtmlFromAssets(path: String) { val html assets.open(path).bufferedReader().use { it.readText() } webView.loadDataWithBaseURL( file:///android_asset/, html, text/html, utf-8, null ) } }这段代码有三个关键点。第一javaScriptEnabled必须为true否则HTML里的JS代码不执行题目点击后一点反应都没有。第二loadDataWithBaseURL的baseUrl传的是file:///android_asset/这样HTML里再引用css/js/img时浏览器会拿这个地址作为相对路径的基准按asset目录去解析。第三use { it.readText() }是Kotlin的简洁写法会自动关闭流比Java里那套try-finally看着舒服这也是混编项目里最常见的Kotlin特色写法。关于网上流传的loadUrl写法区别要讲清楚loadUrl(file:///android_asset/html/quiz_01.html)也能加载但这种方式无法在内存中注入额外逻辑。如果你需要在加载前拼数据、替换模板字符串用loadDataWithBaseURL更灵活。两套方案都行改题库时记得保持一致就行。4. 把HTML题库改造成自己的题目格式、资源路径与JS回调跑通源码只是第一步。要交付得能改成自己的题目。 HTML题库看似自由但要被原生层正确识别需要遵循一套约定题目的选项怎么标记、点击后怎么通知Android、图片资源往哪放。这三件事搞明白替换题库就是复制粘贴的事。4.1 一页一题的HTML模板data-answer与ID约定多数答题源码会约定一页一题或者一页多题一次性渲染。我建议优先用一页一题好处是代码简单、进度容易控制、答完一题切下一页演示效果也干净。每个HTML文件对应一个题目结构大致如下!DOCTYPE html html langzh-CN head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title第 1 题/title link relstylesheet hrefcss/main.css /head body div classquestion>