Capacitor + Vue 3 构建 Android App 的完整流程

从 Web 技术栈到原生 Android App 的打包实践,涵盖开发中遇到的关键问题及解决方案。

一、技术选型

「爻动万象」选择 Capacitor 而非 Cordova 或 React Native,原因很简单:

二、原生开屏页

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