Capacitor + Vue 3 构建 Android App 的完整流程
从 Web 技术栈到原生 Android App 的打包实践,涵盖开发中遇到的关键问题及解决方案。
一、技术选型
「爻动万象」选择 Capacitor 而非 Cordova 或 React Native,原因很简单:
- 项目已经是 Vue 3 + Vite,Capacitor 零配置接入
- Capacitor 8.x 基于现代 WebView,性能更好
- 原生插件生态完善(App、Browser、Haptics 等)
- 构建流程简单:
npm run build → npx cap sync → gradlew assembleDebug
二、原生开屏页
Capacitor App 启动时会有短暂白屏,因为 WebView 需要加载。解决方案是在 index.html 中内联一个原生开屏:
<div id="splash-native">
<div class="glass"><img src="/logo.png"></div>
<div class="title">爻动万象</div>
</div>
<style>
#splash-native {
position: fixed; inset: 0; z-index: 99999;
display: flex; align-items: center; justify-content: center;
flex-direction: column; gap: 28px;
background: #f7f7f5;
}
.glass {
width: 120px; height: 120px; border-radius: 30px;
background: rgba(255,255,255,0.55);
backdrop-filter: blur(24px);
animation: breathe 3s ease-in-out infinite;
}
</style>
Vue 挂载后,用 JS 移除开屏:
const splash = document.getElementById('splash-native')
if (splash) {
splash.classList.add('fade-out')
setTimeout(() => splash.remove(), 600)
}
三、HTTP 明文请求
Android 9+ 默认禁止 HTTP 明文请求。如果后端没有 HTTPS,需要配置 network_security_config.xml:
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">139.224.69.174</domain>
</domain-config>
</network-security-config>
并在 AndroidManifest.xml 中引用:
<application
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config">
最佳实践是上 HTTPS。我们后来配置了 Nginx 反向代理 + Let's Encrypt 证书,彻底解决了这个问题。
四、Android 返回键
Capacitor App 需要手动处理 Android 返回键,否则按返回直接退出:
import { App as CapApp } from '@capacitor/app'
onMounted(async () => {
listener = await CapApp.addListener('backButton', () => {
if (currentTab.value === 'jieguo') {
currentTab.value = 'paipan' // 解卦 → 排盘
} else if (currentTab.value === 'mine') {
currentTab.value = 'paipan' // 我的 → 排盘
} else {
CapApp.exitApp() // 排盘 → 退出
}
})
})
五、JS 混淆防逆向
为了防止 APK 被反编译,使用 vite-plugin-javascript-obfuscator 在构建时混淆代码:
obfuscator({
options: {
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.5,
deadCodeInjection: true,
stringArray: true,
stringArrayEncoding: ['rc4'],
transformObjectKeys: true,
},
})
混淆后代码可读性大幅下降,增加逆向难度。但要注意:混淆会增加构建产物大小,deadCodeInjection 阈值不宜太高。
六、构建流程
# 构建 Web 资源
npm run build
# 同步到 Android 工程
npx cap sync android
# 构建 Debug APK
cd android && ./gradlew assembleDebug
# APK 位置
# android/app/build/outputs/apk/debug/app-debug.apk