Browse Source

feat: isNativeApp

liming 4 weeks ago
parent
commit
6d66112152
8 changed files with 234 additions and 132 deletions
  1. 8 0
      .env
  2. 76 0
      auto-imports.d.ts
  3. 0 61
      capacitor.config.json
  4. 78 0
      capacitor.config.ts
  5. 1 1
      jsconfig.json
  6. 3 2
      package.json
  7. 4 1
      src/api/axios.js
  8. 64 67
      vite.config.js

+ 8 - 0
.env

@@ -0,0 +1,8 @@
+
+
+
+# development path
+VITE_DEV_PATH='https://wallet.angeltokens.io' 
+
+# production path
+VITE_PRO_PATH='https://wallet.angeltokens.io'

+ 76 - 0
auto-imports.d.ts

@@ -0,0 +1,76 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// noinspection JSUnusedGlobalSymbols
+// Generated by unplugin-auto-import
+// biome-ignore lint: disable
+export {}
+declare global {
+  const EffectScope: typeof import('vue')['EffectScope']
+  const computed: typeof import('vue')['computed']
+  const createApp: typeof import('vue')['createApp']
+  const customRef: typeof import('vue')['customRef']
+  const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
+  const defineComponent: typeof import('vue')['defineComponent']
+  const effectScope: typeof import('vue')['effectScope']
+  const getCurrentInstance: typeof import('vue')['getCurrentInstance']
+  const getCurrentScope: typeof import('vue')['getCurrentScope']
+  const h: typeof import('vue')['h']
+  const inject: typeof import('vue')['inject']
+  const isProxy: typeof import('vue')['isProxy']
+  const isReactive: typeof import('vue')['isReactive']
+  const isReadonly: typeof import('vue')['isReadonly']
+  const isRef: typeof import('vue')['isRef']
+  const markRaw: typeof import('vue')['markRaw']
+  const nextTick: typeof import('vue')['nextTick']
+  const onActivated: typeof import('vue')['onActivated']
+  const onBeforeMount: typeof import('vue')['onBeforeMount']
+  const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
+  const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
+  const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
+  const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
+  const onDeactivated: typeof import('vue')['onDeactivated']
+  const onErrorCaptured: typeof import('vue')['onErrorCaptured']
+  const onMounted: typeof import('vue')['onMounted']
+  const onRenderTracked: typeof import('vue')['onRenderTracked']
+  const onRenderTriggered: typeof import('vue')['onRenderTriggered']
+  const onScopeDispose: typeof import('vue')['onScopeDispose']
+  const onServerPrefetch: typeof import('vue')['onServerPrefetch']
+  const onUnmounted: typeof import('vue')['onUnmounted']
+  const onUpdated: typeof import('vue')['onUpdated']
+  const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
+  const provide: typeof import('vue')['provide']
+  const reactive: typeof import('vue')['reactive']
+  const readonly: typeof import('vue')['readonly']
+  const ref: typeof import('vue')['ref']
+  const resolveComponent: typeof import('vue')['resolveComponent']
+  const shallowReactive: typeof import('vue')['shallowReactive']
+  const shallowReadonly: typeof import('vue')['shallowReadonly']
+  const shallowRef: typeof import('vue')['shallowRef']
+  const toRaw: typeof import('vue')['toRaw']
+  const toRef: typeof import('vue')['toRef']
+  const toRefs: typeof import('vue')['toRefs']
+  const toValue: typeof import('vue')['toValue']
+  const triggerRef: typeof import('vue')['triggerRef']
+  const unref: typeof import('vue')['unref']
+  const useAttrs: typeof import('vue')['useAttrs']
+  const useCssModule: typeof import('vue')['useCssModule']
+  const useCssVars: typeof import('vue')['useCssVars']
+  const useId: typeof import('vue')['useId']
+  const useLink: typeof import('vue-router')['useLink']
+  const useModel: typeof import('vue')['useModel']
+  const useRoute: typeof import('vue-router')['useRoute']
+  const useRouter: typeof import('vue-router')['useRouter']
+  const useSlots: typeof import('vue')['useSlots']
+  const useTemplateRef: typeof import('vue')['useTemplateRef']
+  const watch: typeof import('vue')['watch']
+  const watchEffect: typeof import('vue')['watchEffect']
+  const watchPostEffect: typeof import('vue')['watchPostEffect']
+  const watchSyncEffect: typeof import('vue')['watchSyncEffect']
+}
+// for type re-export
+declare global {
+  // @ts-ignore
+  export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
+  import('vue')
+}

+ 0 - 61
capacitor.config.json

@@ -1,61 +0,0 @@
-{
-  
-  "appId": "com.example.app", 
-  "appName": "wallet_app", 
-  "webDir": "dist",  
-
-  
-  "server": {
-    "url": "http://192.168.0.59:5173",  
-    "cleartext": true, 
-    "allowNavigation": ["*"] 
-  },
-
-  "plugins": {
-    
-    "SplashScreen": {
-      "launchShowDuration": 3000, 
-      "launchAutoHide": true,
-      "backgroundColor": "#ffffffff", 
-      "androidScaleType": "CENTER_CROP",
-      "showSpinner": false,
-      "androidSpinnerStyle": "large", 
-      "iosSpinnerStyle": "small", 
-      "spinnerColor": "#999999", 
-      "splashFullScreen": true, 
-      "splashImmersive": true, 
-      "androidSplashResourceName": "splash", 
-      "useDialog": false 
-    },
-
-    "CapacitorAssets": {
-      "iconBackgroundColor": "#ffffff"
-    },
-    "plugins": {
-      "PushNotifications": {
-        "presentationOptions": ["badge", "sound", "alert"]
-      }
-    }
-  },
-
-  "assets": {
-    "splash": {
-      "src": "assets/splash.png", 
-      "android": true,
-      "ios": true 
-    }
-  },
-
-  
-  "ios": {
-    "scheme": "App",
-    "allowsInlineMediaPlayback": true, 
-    "scrollEnabled": true, 
-    "preferredContentMode": "Aspect Fit" 
-  },
-
-  "android": {
-    "allowMixedContent": true, 
-    "useLegacyBridge": true 
-  }
-}

+ 78 - 0
capacitor.config.ts

@@ -0,0 +1,78 @@
+import { CapacitorConfig } from '@capacitor/cli';
+
+const config: CapacitorConfig = {
+  appId: 'com.example.app',
+  appName: 'wallet_app',
+  webDir: 'dist',
+
+  // 开发服务器配置(热更新用)
+  // server: {
+  //   url: 'http://192.168.0.59:5173',
+  //   cleartext: true,          // 允许HTTP明文通信(仅开发环境)
+  //   allowNavigation: ['*']    // 允许任意URL导航
+  // },
+  server: {
+    allowNavigation: [
+      "*.angeltokens.io",
+      "*.your-api.com"
+    ]
+  }
+
+  // 插件配置
+  plugins: {
+    SplashScreen: {
+      launchShowDuration: 3000,
+      launchAutoHide: true,
+      backgroundColor: '#ffffffff',  // ARGB格式白色背景
+      androidScaleType: 'CENTER_CROP',
+      showSpinner: false,
+      androidSpinnerStyle: 'large',
+      iosSpinnerStyle: 'small',
+      spinnerColor: '#999999',
+      splashFullScreen: true,
+      splashImmersive: true,
+      androidSplashResourceName: 'splash',
+      useDialog: false
+    },
+
+    CapacitorAssets: {
+      iconBackgroundColor: '#ffffff'  // 应用图标背景色
+    },
+
+    // 注意:原JSON中嵌套了重复的"plugins"键,已修正
+    PushNotifications: {
+      presentationOptions: ['badge', 'sound', 'alert']
+    }
+  },
+
+  // 资源文件配置
+  // assets: {
+  //   splash: {
+  //     src: 'assets/splash.png',  // 启动图路径
+  //     android: true,
+  //     ios: true
+  //   }
+  // },
+
+  // iOS专属配置
+  ios: {
+    scheme: 'App',
+    scrollEnabled: true,
+  },
+
+  // Android专属配置
+  android: {
+    allowMixedContent: true,     // 允许混合HTTP/HTTPS内容
+    useLegacyBridge: true,       // 使用旧版桥接(兼容性)
+
+    // 签名证书配置(建议通过环境变量注入敏感信息)
+    buildOptions: {
+      keystorePath: 'f62.keystore',
+      keystoreAlias: 'f62', //  // 生成时指定的别名
+      keystorePassword:  'LkSvN1Ys',  // 从环境变量读取
+      keystoreAliasPassword:   'LkSvN1Ys'
+    }
+  }
+};
+
+export default config;

+ 1 - 1
jsconfig.json

@@ -6,6 +6,6 @@
     },
     "allowSyntheticDefaultImports": true
   },
-  "include": ["src/**/*.js", "src/**/*.ts", "src/**/*.vue", "src/**/*.tsx"],
+  "include": ["src/**/*.js", "src/**/*.ts", "src/**/*.vue", "src/**/*.tsx", "capacitor.config.ts"],
   "exclude": ["node_modules", "dist"]
 }

+ 3 - 2
package.json

@@ -4,7 +4,7 @@
   "private": true,
   "type": "module",
   "scripts": {
-    "dev": "vite",
+    "dev": "vite --host",
     "s": "npx cap sync",
     "a": "npx cap run android --live-reload --host=192.168.0.59 --port=5173",
     "app": "npx cap run android --live-reload --host=192.168.0.70 --port=5173",
@@ -12,7 +12,7 @@
     "android": "npx cap add android && npx cap sync",
     "android:clean": "(cd android && ./gradlew clean)",
     "build": "vite build && npx cap copy",
-    "build:apk": "vite build && npx cap copy && (cd android && ./gradlew build)",
+    "build:apk": "vite build && npx cap copy && (cd android && ./gradlew assembleRelease)",
     "build:apk:windows": "vite build && npx cap copy && cd android && .\\gradlew.bat build",
     "icon": "npx capacitor-assets generate --android",
     "preview": "vite preview"
@@ -43,6 +43,7 @@
     "pinia": "^3.0.1",
     "qrcode.vue": "^3.6.0",
     "sharp": "^0.34.2",
+    "typescript": "^5.8.3",
     "vant": "^4.9.20",
     "vue": "^3.5.13",
     "vue-i18n": "^11.1.9",

+ 4 - 1
src/api/axios.js

@@ -1,4 +1,5 @@
 import axios from "axios";
+import { Capacitor } from '@capacitor/core';
 import { showNotify } from 'vant';
 import { useSystemStore } from "@/stores/modules/systemStore";
 import { fn_logout } from "@/utils";
@@ -7,8 +8,10 @@ import { fn_logout } from "@/utils";
 const requestMap = new Map();
 const requestCountMap = new Map(); // 用于记录请求的次数
 
+const isNativeApp = Capacitor.isNativePlatform();
+
 const axiosInstance = axios.create({
-  baseURL: import.meta.env.BASE_URL + "api", // 设置 API 基础 URL
+  baseURL: (isNativeApp ? import.meta.env.VITE_PRO_PATH : import.meta.env.BASE_URL) + "/api", // 设置 API 基础 URL
   timeout: 300000, // 设置请求超时时间
 });
 

+ 64 - 67
vite.config.js

@@ -1,83 +1,80 @@
 import { fileURLToPath, URL } from "node:url";
-import fs from 'node:fs';
-
-import { defineConfig } from "vite";
+import { defineConfig, loadEnv } from "vite";
 import vue from "@vitejs/plugin-vue";
 import vueDevTools from "vite-plugin-vue-devtools";
 import vueJsx from "@vitejs/plugin-vue-jsx";
 import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
-import { codeInspectorPlugin } from 'code-inspector-plugin';
-import AutoImport from 'unplugin-auto-import/vite'
+import { codeInspectorPlugin } from "code-inspector-plugin";
+import AutoImport from "unplugin-auto-import/vite";
 
-import { resolve } from "path"; 
+import { resolve } from "path";
 
 // https://vite.dev/config/
-export default defineConfig({
-  base: "./",
-  plugins: [
-    vue(), 
-    vueJsx(),
-    AutoImport({
-      imports:[
-        'vue',
-        'vue-router'
-      ]
-    }),
-    // vueDevTools(),
-    createSvgIconsPlugin({
-      // 指定需要缓存的图标文件夹
-      iconDirs: [ resolve(process.cwd(), "src/assets/svg")],
-      // 指定symbolId格式
-      symbolId: "icon-[dir]-[name]",
-    }),
-    codeInspectorPlugin({
-      bundler: 'vite',
-    }),
-  ],
-  resolve: {
-    alias: {
-      "@": fileURLToPath(new URL("./src", import.meta.url)),
+export default defineConfig(({ mode }) => {
+  const env = loadEnv(mode, process.cwd());
+  return {
+    base: "./",
+    plugins: [
+      vue(),
+      vueJsx(),
+      AutoImport({
+        imports: ["vue", "vue-router"],
+      }),
+      // vueDevTools(),
+      createSvgIconsPlugin({
+        // 指定需要缓存的图标文件夹
+        iconDirs: [resolve(process.cwd(), "src/assets/svg")],
+        // 指定symbolId格式
+        symbolId: "icon-[dir]-[name]",
+      }),
+      codeInspectorPlugin({
+        bundler: "vite",
+      }),
+    ],
+    resolve: {
+      alias: {
+        "@": fileURLToPath(new URL("./src", import.meta.url)),
+      },
     },
-  },
-  css: {
-    // css预处理器
-    preprocessorOptions: {
-      less: {
-        charset: false, //  解决中文乱码
-        javascriptEnabled: true,
-        additionalData:
-          '@import "@/assets/css/global.less";@import "@/assets/css/theme.less";',
+    css: {
+      // css预处理器
+      preprocessorOptions: {
+        less: {
+          charset: false, //  解决中文乱码
+          javascriptEnabled: true,
+          additionalData:
+            '@import "@/assets/css/global.less";@import "@/assets/css/theme.less";',
+        },
       },
     },
-  },
-  build: {
-    minify: true, // 生产环境不生成sourcemap
-    target: "es2015",
-    // 警报门槛,限制大文件大小
-    chunkSizeWarningLimit: 5000,
-    rollupOptions: {
-      external: [], // 外部化处理那些你不想打包进库的依赖
-      // 静态资源分类打包
-      output: {
-        chunkFileNames: "static/js/[name]-[hash].js",
-        entryFileNames: "static/js/[name]-[hash].js",
-        assetFileNames: "static/[ext]/[name]-[hash].[ext]",
+    build: {
+      minify: true, // 生产环境不生成sourcemap
+      target: "es2015",
+      // 警报门槛,限制大文件大小
+      chunkSizeWarningLimit: 5000,
+      rollupOptions: {
+        external: [], // 外部化处理那些你不想打包进库的依赖
+        // 静态资源分类打包
+        output: {
+          chunkFileNames: "static/js/[name]-[hash].js",
+          entryFileNames: "static/js/[name]-[hash].js",
+          assetFileNames: "static/[ext]/[name]-[hash].[ext]",
+        },
       },
     },
-  }, 
-  server: { 
-    host: true,
-    port: 5173,
-    open: true,
-    cors: true, 
-    hmr: true,
-    proxy: {
+    server: {
+      host: true,
+      port: 5173,
+      open: true,
+      cors: true,
+      hmr: true,
+      proxy: {
         "^/api": {
-             target:"https://wallet.angeltokens.io",
-            changeOrigin: true, 
-            // secure: false, 
-        }
+          target: env.VITE_PRO_PATH,
+          changeOrigin: true,
+          // secure: false,
+        },
+      },
     },
-    
-  },
+  };
 });