Aplikasi Anda bilang terputus, bilah menu bilang tersambung, dan lalu lintasnya jelas mengalir. Kesenjangan itu bukan race condition yang bisa Anda perbaiki dengan mencoba ulang: aplikasi dan tunnel adalah proses terpisah, dan objek yang dibaca kode Anda adalah tampilan cache dari konfigurasi yang disimpan sistem. Permukaan Personal VPN Apple adalah API kendali, bukan jalur data, dan sebagian besar perilaku anehnya berasal dari satu fakta itu. Berikut yang sebenarnya terjadi pada setiap panggilan.

Objek manajer adalah tampilan cache, bukan tunnel

NETunnelProviderManager diisi dari penyimpanan preferensi yang dimiliki sistem, jadi propertinya tidak berarti apa-apa sampai loadFromPreferences selesai. Baca connection.status sebelum itu dan Anda mendapat nilai default, itulah sebabnya penyegaran status pertama setelah peluncuran ulang melaporkan terputus padahal tunnel aktif. Muat dulu, lalu baca status dan konfigurasi protokol dari handler penyelesaian yang sama. Amati perubahan berikutnya melalui NEVPNStatusDidChange alih-alih melakukan polling, dan perhatikan bahwa notifikasi juga menyala untuk koneksi yang dimulai On Demand, di mana tidak ada panggilan aplikasi yang bisa mengembalikan apa pun. Hal yang sama berlaku untuk pengaturan protokol: dibaca dari konfigurasi yang dimuat, bukan dari yang dikirim aplikasi.

Tunnel itu sendiri hidup di proses penyedia Network Extension, jadi aplikasi bisa kehilangan statusnya sendiri tanpa kehilangan koneksi. Semua yang ditampilkan antarmuka harus dibangun ulang dari manajer, bukan diingat dari sesi terakhir.

Urutan mulai: simpan, muat, lalu mulai

Koneksi berbasis penyedia membutuhkan tiga langkah secara berurutan. Tulis konfigurasi penyedia dan panggil saveToPreferences, muat manajer agar konfigurasi tersimpan adalah yang Anda pegang, lalu mulai melalui NETunnelProviderSession.startVPNTunnel(). Lewatkan penyimpanan dan mulai tidak punya apa pun untuk dijalankan; muat sebelum menyimpan dan manajer masih mencerminkan konfigurasi lama.

Boolean yang dikembalikan startVPNTunnel hanya mengatakan bahwa permintaan diterima. Kegagalan tingkat penyedia datang kemudian sebagai perubahan status menjadi terputus, yang Anda amati melalui notifikasi NEVPNStatusDidChange, dan handler notifikasi harus membaca ulang connection.status setelah loadFromPreferences karena nilai cache mungkin masih yang lama. Kegagalan tingkat permintaan kembali segera dari bentuk panggilan yang melempar pengecualian, atau melalui parameter keluaran galat dari startVPNTunnelAndReturnError:. Kode yang memperlakukan nilai kembalian sebagai hasil melaporkan koneksi yang tidak pernah terbentuk. Kegagalan senyap lainnya adalah pengenal bundel penyedia yang tidak cocok dengan ekstensi terpasang: permintaan ditolak, dan tidak ada apa pun dalam pesan yang menunjuk ke pengenal itu. Jika pengenalnya salah, permintaan biasanya gagal seketika, sebelum satu baris log penyedia pun muncul.

Memuat ulang preferensi setelah mulai adalah yang membuat layar status benar. Manajer tidak mendorong konfigurasi baru kepada Anda saat sistem mengubahnya.

Materi kepercayaan datang lewat profil, tidak pernah dari kode aplikasi

Aplikasi tidak punya cara yang didukung untuk menambahkan sertifikat akar ke penyimpanan kepercayaan iOS, jadi konfigurasi Personal VPN hanya bisa merujuk materi yang sudah dipercaya perangkat: rantai yang dibentuk profil terpasang, manajemen perangkat, atau CA yang dipercaya sistem karena alasan lain. Aplikasi yang membuat CA-nya sendiri saat peluncuran pertama dan berharap sistem mengakuinya akan gagal validasi di dalam penyedia, tempat antarmuka aplikasi tidak bisa melihat alasannya.

Perlakukan batas itu sebagai kendala desain sebagaimana adanya dan kirimkan jangkar kepercayaan bersama profil pendaftaran. Jaga autentikasi VPN terpisah dari keputusan kepercayaan, karena keduanya gagal di tempat berbeda dan di-debug oleh orang berbeda.

Penghitung datang dari antarmuka, bukan dari API VPN

Manajer mengekspos status dan konfigurasi, dan tidak ada yang menghitung byte per tunnel. Jika Anda butuh angka pemakaian, panggil getifaddrs() dan baca if_data untuk antarmuka yang relevan: en0 untuk Wi-Fi, antarmuka pdp_ip untuk seluler, dan perangkat utun untuk tunnel itu sendiri. Penghitung utun menggambarkan lalu lintas dalam dan mencakup beban overhead protokol.

Angka-angka itu perkiraan, bukan akuntansi per aplikasi, dan direset saat antarmuka dibuat ulang. Beri label seperti itu di antarmuka, atau seseorang akan memakainya untuk menagih pelanggan. Jika Anda butuh angka per aplikasi, Anda butuh mekanisme yang sama sekali berbeda, bukan pembacaan bidang ini yang lebih baik.

Pembersihan ada di stopVPNTunnel, bukan di terminasi

applicationWillTerminate memberi Anda beberapa detik sebelum sistem dapat mematikan proses, yang bukan tempat andal untuk membongkar koneksi. Kirim penghentian ke stopVPNTunnel() atau tangani di callback penghentian penyedia, dan simpan pengenal manajer atau konfigurasi yang Anda mulai agar penghentian menyasar koneksi itu alih-alih setiap konfigurasi di perangkat.

Simpan pengenal itu bersama profil miliknya, karena objek manajer tidak mencatat konfigurasi mana yang dipilih pengguna. Dan ingat bahwa koneksi yang dinaikkan On Demand tidak punya panggilan aplikasi di belakangnya sama sekali, jadi layar status tetap harus memuat preferensi sebelum menggambar apa pun.

Artikel terkait