1# VPN应用开发指南 2 3## 简介 4 5VPN,即虚拟专用网络(Virtual Private Network),是在公用网络上建立专用网络的一种技术。在VPN网络中,任意两个节点间的连接并非依赖传统专用网络所需要的端到端的物理链路,而是构建在公用网络服务商提供的平台(如Internet)之上的逻辑网络。用户数据在这一逻辑链路中进行传输。 6 7OpenHarmony为开发者提供了用于创建VPN的API解决方案。本文将指导您如何开发自己的VPN客户端。 8 9> **说明:** 10> 11> 为了保证应用的运行效率,所有API调用都是异步的,对于异步调用的API均提供了Promise的方式,以下示例均采用Promise方式,更多方式可以查阅[API参考](../reference/apis-network-kit/js-apis-net-vpnExtension.md)。 12 13## VPN应用的显示体验 14 15借助系统提供的VPN Extension接口开发者可以构建支持不同协议的VPN服务。OpenHarmony系统提供了界面 (UI) 使用户可以了解当前VPN应用服务的启动和连接: 16 17- 在VPN应用首次启动连接之前,系统会显示VPN连接授权对话框。该对话框会提示用户是否信任该VPN应用并接受VPN连接请求。 18- 当VPN启动连接成功时,状态栏显示一个VPN (钥匙) 图标以提醒用户VPN处于连接状态。 19 20为了使用户可以方便的查看和配置,您的VPN应用还需要提供以下界面: 21 22- 用于手动启动和停止连接的控件。 23- 当VPN启动连接时,在通知栏显示VPN应用的连接状态或提供网络统计信息 (如连接时长、流量等) 。点击该通知能够将您的VPN应用调入前台。 24 25## 接口说明 26 27完整的JS API说明以及示例代码请参考:[VPN扩展应用API](../reference/apis-network-kit/js-apis-net-vpnExtension.md)。 28 29## 创建VPN Extension Ability 30 31如果想使您的应用支持VPN能力,首先您需要创建一个继承于VpnExtensionAbility的extensionAbilities。 32 33```ts 34// 举例:在应用的module.json5中定义MyVpnExtAbility 35"extensionAbilities": [ 36 { 37 "name": "MyVpnExtAbility", 38 "description": "vpnservice", 39 "type": "vpn", 40 "srcEntry": "./ets/serviceextability/MyVpnExtAbility.ts" 41 } 42] 43``` 44 45> **注意:** 46> 47> 如果DevEco Studio工具提示不能识别"type": "vpn",需要您手动在SDK的toolchains\modulecheck\module.json文件中,给extensionAbilities对应的type枚举添加"vpn"定义,并清除build缓存。 48 49接下来您需要在创建的VpnExtensionAbility中实现VPN的配置、启动和停止操作: 50 51- 建立一个VPN的网络隧道,以TCP隧道为例(参考本文下方VPN Demo示例工程文件[vpn_client](https://gitee.com/openharmony/applications_app_samples/blob/master/code/BasicFeature/Connectivity/VPN/entry/src/main/cpp/vpn_client.cpp)的TcpConnect()方法); 52- 通过VpnConnection.[protect](../reference/apis-network-kit/js-apis-net-vpnExtension.md#protect)保护前一步建立的TCP隧道; 53- 构建VPN Config参数,参考[VPN Config参数说明](#vpn-config参数说明); 54- 通过VpnConnection.[create](../reference/apis-network-kit/js-apis-net-vpnExtension.md#create)建立VPN网络连接; 55- 处理虚拟网卡的数据,如:读写操作。 56 57 58## 启动VPN Extension Ability 59 60当VPN应用启动VPN连接时,需要调用startVpnExtensionAbility接口,携带需要启动的VpnExtensionAbility信息,其中bundleName需要与您的VPN应用bundleName一致,abilityName为您在前面创建的VpnExtensionAbility名。您可参考如下示例: 61 62```ts 63import { common, Want } from '@kit.AbilityKit'; 64import { vpnExtension } from '@kit.NetworkKit'; 65 66let want: Want = { 67 deviceId: "", 68 bundleName: "com.example.myvpndemo", 69 abilityName: "MyVpnExtAbility", 70}; 71 72@Entry 73@Component 74struct Index { 75 @State message: string = 'Hello World'; 76 77 build() { 78 Row() { 79 Column() { 80 Text(this.message) 81 .fontSize(50) 82 .fontWeight(FontWeight.Bold).onClick(() => { 83 console.info("btn click") }) 84 Button('Start Extension').onClick(() => { 85 vpnExtension.startVpnExtensionAbility(want); 86 }).width('70%').fontSize(45).margin(16) 87 }.width('100%') 88 }.height('100%') 89 } 90} 91``` 92 93如果您的VPN应用未获取用户信任,系统将弹出VPN连接的授权对话框,当获取用户授权后,系统将自动调用并启动您实现的VPN Extension Ability的[onCreate](../reference/apis-network-kit/js-apis-VpnExtensionAbility.md#vpnextensionabilityoncreate)方法将被调用。 94 95目前系统仅支持启动一个VPN连接服务,当VPN已经启动时应用新调用启动接口会收到系统拒绝错误,此时建议您的应用可以提醒用户先断开当前已经激活的VPN应用连接。 96 97 98 99## 停止VPN Extension Ability 100 101当VPN应用需要停止VPN连接时,需要调用stopVpnExtensionAbility接口,携带需要停止的VpnExtensionAbility信息。系统会对调用方做权限校验,stopVpnExtensionAbility的调用方应用必须获取了用户的VPN信任授权,且只允许停止应用自己启动的VpnExtensionAbility,所以接口传入的参数中bundleName需要与您的VPN应用bundleName一致,abilityName为指定停止VPN的VpnExtensionAbility名。 102 103您可参考如下示例: 104 105```ts 106import { common, Want } from '@kit.AbilityKit'; 107import { vpnExtension } from '@kit.NetworkKit'; 108 109let want: Want = { 110 deviceId: "", 111 bundleName: "com.example.myvpndemo", 112 abilityName: "MyVpnExtAbility", 113}; 114 115@Entry 116@Component 117struct Index { 118 @State message: string = 'Hello World'; 119 120 build() { 121 Row() { 122 Column() { 123 Text(this.message) 124 .fontSize(50) 125 .fontWeight(FontWeight.Bold).onClick(() => { 126 console.info("btn click") }) 127 Button('Start Extension').onClick(() => { 128 vpnExtension.startVpnExtensionAbility(want); 129 }).width('70%').fontSize(45).margin(16) 130 Button('Stop Extension').onClick(() => { 131 console.info("btn end") 132 vpnExtension.stopVpnExtensionAbility(want); 133 }).width('70%').fontSize(45).margin(16) 134 135 }.width('100%') 136 }.height('100%') 137 } 138} 139``` 140 141stopVpnExtensionAbility后,您的VPN Extension Ability的[onDestroy](../reference/apis-network-kit/js-apis-VpnExtensionAbility.md#vpnextensionabilityondestroy)方法将被调用,您可在此时destroy vpn连接。 142 143```ts 144import { vpnExtension, VpnExtensionAbility } from '@kit.NetworkKit'; 145import { common, Want } from '@kit.AbilityKit'; 146import { BusinessError } from '@kit.BasicServicesKit'; 147 148let context: vpnExtension.VpnExtensionContext; 149export default class MyVpnExtAbility extends VpnExtensionAbility { 150 onDestroy() { 151 let VpnConnection : vpnExtension.VpnConnection = vpnExtension.createVpnConnection(context); 152 console.info("vpn createVpnConnection: " + JSON.stringify(VpnConnection)); 153 VpnConnection.destroy().then(() => { 154 console.info("destroy success."); 155 }).catch((error : BusinessError) => { 156 console.error("destroy fail" + JSON.stringify(error)); 157 }); 158 } 159} 160``` 161 162## 服务生命周期 163 164为了保障设备的网络连接,当系统观察到VPN相关应用出现异常时会主动停止VPN连接: 165 166- 当调用startVpnExtensionAbility接口的应用进程退出时。 167- 当VPN服务进程销毁时。 168 169## VPN Config参数说明 170 171| 名称 | 类型 | 必填 | 说明 | 172| ------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 173| addresses | Array\<[LinkAddress](../reference/apis-network-kit/js-apis-net-connection.md#linkaddress)\> | 是 | VPN虚拟网卡的IP地址。 | 174| routes | Array\<[RouteInfo](../reference/apis-network-kit/js-apis-net-connection.md#routeinfo)\> | 否 | VPN虚拟网卡的路由信息(目前最多可配置1024条路由)。 | 175| dnsAddresses | Array\<string\> | 否 | DNS服务器地址信息。配置后VPN白名单的应用访问网络时使用这些DNS服务器,不配置则使用系统分配的DNS服务器地址。 | 176| searchDomains | Array\<string\> | 否 | DNS的搜索域列表。 | 177| mtu | number | 否 | 最大传输单元MTU值(单位:字节)。 | 178| isIPv4Accepted | boolean | 否 | 是否支持IPV4,默认值为true。 | 179| isIPv6Accepted | boolean | 否 | 是否支持IPV6,默认值为false。 | 180| isInternal | boolean | 否 | 是否支持内置VPN,默认值为false。 | 181| isBlocking | boolean | 否 | 是否阻塞模式,默认值为false。 | 182| trustedApplications | Array\<string\> | 否 | VPN生效的应用白名单信息,string类型表示的包名。 | 183| blockedApplications | Array\<string\> | 否 | 不生效VPN的应用黑名单信息,string类型表示的包名。 | 184 185**示例:** 186 187```ts 188import { vpnExtension} from '@kit.NetworkKit'; 189 190let vpnConfig: vpnExtension.VpnConfig = { 191 // 配置VPN虚拟网卡的IP地址 192 addresses: [{ 193 address: { 194 address:'192.x.x.5', 195 family:1 196 }, 197 prefixLength:24 198 }], 199 // 配置路由参数 200 routes: [{ 201 // VPN虚拟网卡接口名固定为“vpn-tun” 202 interface: 'vpn-tun', 203 destination: { 204 address: { 205 address:'10.x.x.8', 206 family:1, 207 port:8080 208 }, 209 prefixLength:24 210 }, 211 gateway: { 212 address:'10.x.x.5', 213 family:1, 214 port:8080 215 }, 216 hasGateway: false, 217 isDefaultRoute: false, 218 }], 219 // 配置最大传输单元值 220 mtu: 1400, 221 // 配置VPN使用的DNS服务器, 222 dnsAddresses: ['223.x.x.5', '223.x.x.6'], 223 // VPN生效白名单的应用 224 trustedApplications: ['com.test.browser'], 225 // 不生效VPN黑名单的应用 226 blockedApplications: ['com.test.games'], 227} 228let context: vpnExtension.VpnExtensionContext; 229 230function vpnCreate(){ 231 let VpnConnection: vpnExtension.VpnConnection = vpnExtension.createVpnConnection(context); 232 VpnConnection.create(vpnConfig).then((data) => { 233 console.info("vpn create " + JSON.stringify(data)); 234 }) 235} 236``` 237 238 239 240## VPN Demo示例 241 242OpenHarmony开源项目包含一个名为[VPN](https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Connectivity/VPN)的示例应用。此应用展示了如何设置和连接 VPN 服务。 243 244 245 246