如何在无网络的Jetpack Compose安卓应用中显示LaTeX或数学公式?
如何在无网络的Jetpack Compose安卓应用中显示LaTeX或数学公式?
我之前也踩过类似的坑,很多库要么偷偷依赖网络,要么配置起来有各种小问题,这里给你几个亲测有效的离线方案:
方案一:用KaTeX本地渲染(推荐,轻量且渲染快)
KaTeX是轻量型的LaTeX渲染库,完全支持离线使用,只需要把它的核心资源打包到项目里就行:
准备离线资源
下载KaTeX的压缩包后,解压出katex.min.js、katex.min.css,还有关键的fonts文件夹(缺了字体公式会显示乱码),把它们都放到项目的src/main/assets/katex/目录下。Compose组件实现
在Compose里我们可以用AndroidView嵌入WebView,加载本地HTML来渲染公式:@Composable fun OfflineKaTeXView(latexText: String) { AndroidView( factory = { context -> WebView(context).apply { settings.javaScriptEnabled = true settings.allowFileAccess = true // 强制禁止网络请求,确保完全离线 settings.blockNetworkLoads = true // 拼接本地HTML模板,传入LaTeX内容 val htmlContent = """ <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="file:///android_asset/katex/katex.min.css"> <script src="file:///android_asset/katex/katex.min.js"></script> </head> <body style="margin:0; padding:8px;"> <span id="formula"></span> <script> katex.render("$latexText", document.getElementById("formula"), { throwOnError: false // 忽略渲染错误,避免应用崩溃 }); </script> </body> </html> """.trimIndent() loadDataWithBaseURL("file:///android_asset/", htmlContent, "text/html", "UTF-8", null) } }, update = { webView -> // 更新公式时重新加载HTML val updatedHtml = """ <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="file:///android_asset/katex/katex.min.css"> <script src="file:///android_asset/katex/katex.min.js"></script> </head> <body style="margin:0; padding:8px;"> <span id="formula"></span> <script> katex.render("$latexText", document.getElementById("formula"), { throwOnError: false }); </script> </body> </html> """.trimIndent() webView.loadDataWithBaseURL("file:///android_asset/", updatedHtml, "text/html", "UTF-8", null) } ) }使用组件
在你的Compose界面里直接调用即可:OfflineKaTeXView(latexText = "E=mc^2 \\quad \\text{or} \\quad \\int_{a}^{b} f(x) dx")
方案二:MathJax本地渲染(功能更全,适合复杂公式)
如果你的公式用到了KaTeX不支持的复杂LaTeX语法,可以用MathJax,步骤类似:
- 下载MathJax的离线包,把整个MathJax文件夹放到
assets目录下。 - 同样用
AndroidView包裹WebView,加载本地HTML调用MathJax渲染:@Composable fun OfflineMathJaxView(latexText: String) { AndroidView( factory = { context -> WebView(context).apply { settings.javaScriptEnabled = true settings.blockNetworkLoads = true val htmlContent = """ <!DOCTYPE html> <html> <head> <script src="file:///android_asset/MathJax/es5/tex-mml-chtml.js"></script> <script> MathJax.config = { loader: { load: ['[tex]/ams'] }, tex: { packages: {'[+]': ['ams']} } }; </script> </head> <body style="margin:0; padding:8px;"> $$ $latexText $$ </body> </html> """.trimIndent() loadDataWithBaseURL("file:///android_asset/", htmlContent, "text/html", "UTF-8", null) } }, update = { webView -> val updatedHtml = """ <!DOCTYPE html> <html> <head> <script src="file:///android_asset/MathJax/es5/tex-mml-chtml.js"></script> <script> MathJax.config = { loader: { load: ['[tex]/ams'] }, tex: { packages: {'[+]': ['ams']} } }; </script> </head> <body style="margin:0; padding:8px;"> $$ $latexText $$ </body> </html> """.trimIndent() webView.loadDataWithBaseURL("file:///android_asset/", updatedHtml, "text/html", "UTF-8", null) } ) }
关键注意事项
- 字体资源一定要打包,不然公式会显示成方块或乱码;
- 开启
throwOnError: false可以避免因LaTeX语法错误导致应用崩溃; - 也可以把HTML模板抽成单独的文件放到assets里,再通过JS接口传递LaTeX内容,这样代码会更整洁。
备注:内容来源于stack exchange,提问作者Ion Petrea
相关产品推荐
相关产品推荐

