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