更新记录

1.0.4(2026-05-29)

使Android和鸿蒙保持统一

1.0.3(2026-05-29)

修复鸿蒙启动后杀死进行再进入app崩溃问题

1.0.2(2026-05-29)

添加对鸿蒙系统的支持

查看更多

平台兼容性

uni-app(5.08)

Vue2 Vue3 Chrome Safari app-vue app-vue插件版本 app-nvue Android Android插件版本 iOS 鸿蒙
- - 1.0.0 - 5.0 1.0.0 -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(5.08)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - - -

sq-atrust

插件说明

本插件支持 uni-app 和 uni-app x 项目深信服SDK只能真机环境下运行调试。

获取插件对象

import * as aTrustVPN from "@/uni_modules/sq-atrust";

演示界面

<template>
  <view class="content">
    <view class="logo">
      <text class="txt"><image class="txt" id="d2"></image></text>
      <text class="tip">测试Demo</text>
    </view>
    <form @submit="formSubmit">
    <view class="form-box">
        <view class="row-input">
            <text style="width: 110upx;margin-right: 0px;"> VPN地址</text><input type="text" name="mVpnAddress" :value="mVpnAddress" placeholder="服务器" />
        </view>
    <text  class="logo1 tip">账号密码登录</text>
    <view class="row-input">
      <image style="margin-right: 1px;"  ></image>
      <input type="text" name="mUserName" :value="mUserName" placeholder="账号" />
    </view>
    <view class="row-input">
      <image style="margin-right: 1px;" > </image>
      <input type="password" name="mUserPassword" :value="mUserPassword" placeholder="请输入密码"  />
    </view>
    <button class="login-btn" :loading='loading' form-type='submit'>登录</button>
    <button class="login-btn" @click="openSpa" >SPA配置</button>
    <button class="login-btn" @click="logoutVPN" >VPN注销</button>
    </view>
    </form>
    <!--需要自己引入插件,作用就是弹框设置SPA或者修改密码-->
    <uni-popup ref="popup" type="dialog">
      <uni-popup-input2-dialog
          ref="dialog"
          :title="'修改密码'"
          :mode="'input'"
          :double-input="true"
          :value="''"
          :value2="''"
          :placeholder1="'旧密码'"
          :placeholder2="'新密码'"
          @confirm="handleConfirm"
          @close="handleClose"
      />
    </uni-popup>

    <uni-popup ref="inputDialog" type="dialog">
      <uni-popup-input-dialog ref="inputClose"  mode="input" title="SPA配置" :value=mSpa
                              placeholder="输入SPA值" @confirm="setSpa"></uni-popup-input-dialog>
    </uni-popup>

  </view>
</template> 

开启全局监听

在根目录下App.vue中添加
import * as aTrustVPN from "@/uni_modules/sq-atrust";
  onLaunch: function () {
    //#ifdef APP-PLUS || APP-HARMONY
    console.log("-------app-start--------")
    console.log("[App TRACE-1] onLaunch 触发, urls.mode=" + urls.mode)
    if(urls.mode == 3) {
      // 延迟初始sdk,避免WebView引擎在磁盘缓存fd活跃时
      // 因VPN网络配置变更导致SIGTRAP(TRAP_BRKPT)崩溃
      // WebView的Chromium引擎在disk_cache::SimpleFileTracker::Close中
      // 对已失效的fd执行PAC_CheckError触发TRAP_BRKPT
      console.log("[App TRACE-2] 延迟调用 initSDK (1秒后),等待WebView引擎完成初始化")
      setTimeout(() => {
      console.log("[App TRACE-2.1] 延迟到期,开始调用 initSDK")
      aTrustVPN.initSDK(() => {
        // 初始化成功后才执行
        console.log("[App TRACE-3] SDK initSDK 回调触发,开始配置VPN")
        // 注册事件监听
        // 注册注销监听
        aTrustVPN.onLogout((type, message) => {
          console.log("[App TRACE-4] 收到注销事件", type, message);
          this.loginVPN();
        });
        aTrustVPN.onGenericNotify((notification) => {
          const {type, message, code} = notification;
          console.log('[App TRACE-5] 收到通用通知:', {type, message, code});

          switch (type) {
            case "SFNotificaitonTypeTicketAuthSuccess":
              console.log('[App TRACE-6] 认证成功');
              break;

            case "SFNotificaitonTypeTicketAuthFailed":
              console.error('[App TRACE-7] 认证失败:', message);
              break;

            case "SFNotificaitonTypeConnectedToProxy":
              console.log('[App TRACE-8] 已连接到代理');
              break;

            case "SFNotificaitonTypeDisconnectFromProxy":
              console.log('[App TRACE-9] 已断开连接,尝试重连...');
              setTimeout(() => {
                this.loginVPN();
              }, 500);
              break;

            default:
              console.log('[App TRACE-10] 未知通知类型:', type, message);
              break;
          }
        });

        // 注册隧道状态监听
        aTrustVPN.onTunnelStatus(
          (status) => {
            console.log('[App TRACE-11] 隧道状态变化:', status);
          },
          (msg) => {
            console.log('[App TRACE-12] 隧道启动完成: errCode=' + msg.errCode + ', errStr=' + msg.errStr);
          },
          () => {
            console.log('[App TRACE-13] 隧道已停止');
          }
        );

        console.log("[App TRACE-14] 尝试免密登录 autoTicket")
        let ticketStatus = aTrustVPN.autoTicket()
        console.log('[App TRACE-15] 免密登录结果:', ticketStatus)
        if (!ticketStatus) {
          // 免密失败,需要手动认证
          console.log('[App TRACE-16] 免密登录失败,检查SPA种子, isSpaSeedExist=' + aTrustVPN.isSpaSeedExist(this.mVpnAddress))
          if (!aTrustVPN.isSpaSeedExist(this.mVpnAddress)) {
            console.log('[App TRACE-17] SPA种子不存在,调用setupSpaAndLogin')
            this.setupSpaAndLogin();
          } else {
            console.log('[App TRACE-18] SPA种子已存在,直接loginVPN')
            this.loginVPN();
          }
        }
      });
      }, 1000);
    }
    //#endif 

  }, 
  //从前台进入后台
  onHide: function () {
    //#ifdef APP-PLUS
    // 后台静默更新
    checkappupdate.checkWgt();
    //#endif
    //#ifdef APP-HARMONY
    // 鸿蒙端:进入后台时不主动停止VPN和注销SDK
    // 原因:
    // 1. onHide只是进入后台,用户可能还会切回来,不应断开VPN
    // 2. stopTunnel+logout会触发SDK异步回调,在应用销毁阶段访问已失效的原生对象
    // 3. 如果系统杀进程,VPN状态标记(wasVpnActiveOnLastExit)会在下次启动时处理
    // 4. 真正需要清理的是onDestroy/onAbilityDestroy,而非onHide

      console.log("[App] onHide: 进入后台,保持VPN连接,不主动注销SDK");

    //#endif
  }
}
</script>

登录页面

data() {
    return {
        showSpa:false, 
        showRepw:false,
        oldPassword:'',
        newPassword:'',
        mSpa:'aaaaaa',
        mVpnAddress: 'https://IP:端口/', 
        mUserName: 'xxx',
        mUserPassword: 'bbbb',
    }
},

设置SPA安全码

methods: {
    setSpa() {
        //都需要需要添加空判断
      if(!this.mVpnAddress){
        util.toastError('请设置请求地址!')
        return
      }
      if(!aTrustVPN.isSpaSeedExist(this.mVpnAddress)){
        const config={"var1":this.mVpnAddress, "var2":this.mSpa,
          success: (e) => { //已经登陆
            util.toastSuccess('SPA设置成功!')
            this.$refs.inputDialog.close()
            },
          fail: (e) => {
            util.toastError('SPA设置失败!')
          },
          complete: (e) => { console.log('前端接收结果',result)
            uni.hideLoading();
          },
        }
        aTrustVPN.setSpaConfig(config)
      }else{
        util.toastSuccess('SPA设置成功!')
        this.$refs.inputDialog.close()
      }
    },
    loginVPN() {
      if(!(this.mVpnAddress && this.mUserName && this.mUserPassword)){
        util.toastError('缺失必要输入值!')
        return
      }
      if (this.getAuthStatus() != "AuthStatusAuthOk") {
        uni.showLoading({
          title: '请稍候...'
        })
        let loginConfig = {
          "var1": this.mVpnAddress, "var2": this.mUserName, "var3": this.mUserPassword,
          success: (result) => {
            uni.hideLoading();
            console.log(result)
            if (result.currentAuthType == 'AUTH_TYPE_NONE') {
              util.toastSuccess('VPN认证成功!')
              uni.reLaunch({
                url: '/pages/auth/login'
              });
            }
          },
          fail: (e) => {
            uni.hideLoading();
            console.log(e);
          },
          complete: (result) => {
            console.log(result)
            uni.hideLoading();
            //修改账号密码
            if (resutl.name() == 'AUTH_TYPE_PASSWORD') {
              //跳转到修改用户名密码界面
              this.openDialog();
            }
          },
        }
        aTrustVPN.startPrimaryAuth(loginConfig)
      }else {
        util.toastSuccess('VPN认证成功!')
        uni.reLaunch({
          url: '/pages/auth/login'
        });
      }
    },
    logoutVPN() {
      if(this.getAuthStatus()=="AuthStatusAuthOk"){
            aTrustVPN.logout();
      }else{
        util.toastSuccess('尚未登录!')
      }
    },
    getAuthStatus() { 
      let res = aTrustVPN.getAuthStatus();
      console.log(res);
      return res;
    },
    loginAutoTicket() {
      //自动免密上线接口,该接口可以实现免密认证。
      if(this.getAuthStatus()!="AuthStatusAuthOk"){
        let res= aTrustVPN.autoTicket();
        console.log(res,this.getAuthStatus());
        return res;
      }
      return false;
    },
     formSubmit: function(e) {
      if(!aTrustVPN.isSpaSeedExist(this.mVpnAddress)){
        util.toastError('请先设置SPA!')
        return
      }
      this.loginVPN()
    }
}

隐私、权限声明

1. 本插件需要申请的系统权限列表:

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.BLUETOOTH" />

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据,插件相关功能调用神奇提供的原生SDK

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率: