1 Commits

Author SHA1 Message Date
MacPro cee99963ef 1
1
2024-10-18 11:11:27 +08:00
264 changed files with 25891 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 sail-tunnel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+1
View File
@@ -0,0 +1 @@
include: package:flutter_lints/flutter.yaml
+13
View File
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
+108
View File
@@ -0,0 +1,108 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdk 34
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
main.jniLibs.srcDirs = ['libs', 'src/main/jniLibs']
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.vpntunnel.vpnzeus"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 28
//noinspection ExpiredTargetSdkVersion
// targetSdkVersion 34
compileSdk 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
// ndk {
// abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', "x86_64"
// }
// dexOptions {
// incremental true
// javaMaxHeapSize "4g"
// preDexLibraries true
// dexInProcess = true
// }
ndk {
if (!project.hasProperty('target-platform')) {
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
} else {
def platforms = project.property('target-platform').split(',')
def platformMap = [
'android-arm' : 'armeabi-v7a',
'android-arm64': 'arm64-v8a',
'android-x86' : 'x86',
'android-x64' : 'x86_64',
]
abiFilters = platforms.stream().map({ e ->
platformMap.containsKey(e) ? platformMap[e] : e
}).toArray()
}
}
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation 'androidx.work:work-runtime-ktx:2.7.1'
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation "dnsjava:dnsjava:3.5.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
}
@@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.sail_tunnel.sail",
"variantName": "profile",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 3,
"versionName": "1.0.2",
"outputFile": "app-profile.apk"
}
],
"elementType": "File"
}
@@ -0,0 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sail_tunnel.sail">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
</manifest>
@@ -0,0 +1,87 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sail_tunnel.sail">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>
<uses-feature
android:name="android.software.leanback"
android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
/>
<application
android:label="UUVPN"
android:name="${applicationName}"
android:icon="@mipmap/app_icon"
android:largeHeap="true"
android:supportsRtl="true"
android:allowBackup="true"
android:hardwareAccelerated="false">
<!-- android:icon="@mipmap/ic_launcher"-->
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="false"
android:windowSoftInputMode="adjustResize"
>
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service
android:name=".TunnelService"
android:enabled="true"
android:permission="android.permission.BIND_VPN_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="android.net.VpnService"/>
</intent-filter>
</service>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2"/>
</application>
</manifest>
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,54 @@
package com.sail_tunnel.sail
import android.app.*
import android.content.*
import android.net.ConnectivityManager
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.core.content.getSystemService
import kotlinx.coroutines.DEBUG_PROPERTY_NAME
import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
import kotlin.reflect.KClass
import androidx.work.Configuration
import com.sail_tunnel.sail.utils.DeviceStorageApp
object Core : Configuration.Provider {
lateinit var app: MainActivity
@VisibleForTesting set
lateinit var configureIntent: (Context) -> PendingIntent
val activity by lazy { app.getSystemService<ActivityManager>()!! }
val connectivity by lazy { app.getSystemService<ConnectivityManager>()!! }
val deviceStorage by lazy { DeviceStorageApp(app) }
fun init(app: MainActivity, configureClass: KClass<out Any>) {
this.app = app
this.configureIntent = {
PendingIntent.getActivity(it, 0, Intent(it, configureClass.java)
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), PendingIntent.FLAG_IMMUTABLE)
}
// overhead of debug mode is minimal: https://github.com/Kotlin/kotlinx.coroutines/blob/f528898/docs/debugging.md#debug-mode
System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON)
Timber.plant(object : Timber.DebugTree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (t == null) {
if (priority != Log.DEBUG || BuildConfig.DEBUG) Log.println(priority, tag, message)
} else {
if (priority >= Log.WARN || priority == Log.DEBUG) Log.println(priority, tag, message)
}
}
})
}
override fun getWorkManagerConfiguration() = Configuration.Builder().apply {
setDefaultProcessName(app.packageName + ":bg")
setMinimumLoggingLevel(if (BuildConfig.DEBUG) Log.VERBOSE else Log.INFO)
setExecutor { GlobalScope.launch { it.run() } }
setTaskExecutor { GlobalScope.launch { it.run() } }
}.build()
}
@@ -0,0 +1,160 @@
package com.sail_tunnel.sail
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.VpnService
import android.os.BatteryManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import com.sail_tunnel.sail.services.VpnState
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.android.FlutterView
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
import java.io.File
class MainActivity: FlutterActivity() {
private val channel = "com.vpntunnel.vpnzeus/vpn_manager"
private fun getServiceIntent(): Intent {
return Intent(this, TunnelService::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Core.init(this, MainActivity::class)
GeneratedPluginRegistrant.registerWith(FlutterEngine(this))
GeneratedPluginRegister.registerGeneratedPlugins(FlutterEngine(this));
// MethodChannel(FlutterView(this), channel).setMethodCallHandler { call, result ->
// if (call.method == "getBatteryLevel") {
// val batteryLevel : Int = getBatteryLevel()
//
// if (batteryLevel != -1) {
// result.success(batteryLevel)
// } else {
// result.error("UNAVAILABLE", "Battery level not available.", null)
// }
// } else {
// Log.e("user_debug", "getBatteryLevel is not method of called")
// result.notImplemented()
// }
// }
}
private fun getBatteryLevel(): Int {
val batteryLevel: Int
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
} else {
val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
}
return batteryLevel
}
override fun onResume() {
super.onResume()
}
override fun onPause() {
super.onPause()
}
private fun getVPNConnectionStatus(): Boolean? {
val context = this@MainActivity
val connectivityManager =
context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
val networks = connectivityManager.allNetworks
//val TAG = "getVPNConnectionStatus"
//Log.i(TAG, "Network count: " + networks.size);
var hasvpn = false
for (i in 0 until networks.size) {
// connectivityManager.getNetworkCapabilities()
val caps: NetworkCapabilities? = connectivityManager.getNetworkCapabilities(networks.get(i))
hasvpn = caps?.hasTransport(NetworkCapabilities.TRANSPORT_VPN) == true
// Log.i(TAG, "Network " + i + ": " + networks.get(i).toString())
// Log.i(TAG, "VPN transport is: " + caps?.hasTransport(NetworkCapabilities.TRANSPORT_VPN))
// Log.i(TAG, "NOT_VPN capability is: " + caps?.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) )
}
return hasvpn
// val activeNetwork = connectivityManager.activeNetwork
// val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
//
// return networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
}
override fun configureFlutterEngine( flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel).setMethodCallHandler {
call, result ->
// This method is invoked on the main thread.
if (call.method == "getStatus") {
result.success(getVPNConnectionStatus())
} else if (call.method == "toggle") {
val intent = VpnService.prepare(this)
if (intent != null) {
startActivityForResult(intent, 0)
result.success(false)
} else {
startService(getServiceIntent())
result.success(true)
}
} else if (call.method == "getTunnelLog") {
// val context = Core.deviceStorage
// val configRoot = context.noBackupFilesDir
// val config = File(configRoot, VpnState.LEAF_LOG_FILE).readText()
// result.success(config)
} else if (call.method == "getTunnelConfiguration") {
val context = Core.deviceStorage
val configRoot = context.noBackupFilesDir
val config = File(configRoot, VpnState.CONFIG_FILE).readText()
val TAGs = "getVPNConnectionStatus"
Log.i(TAGs, config);
result.success(config)
} else if (call.method == "setTunnelConfiguration") {
try {
val context = Core.deviceStorage
val configRoot = context.noBackupFilesDir
val TAGs = "setTunnelConfiguration"
Log.i(TAGs, call.arguments.toString());
File(configRoot, VpnState.CONFIG_FILE).writeText(call.arguments.toString())
}catch (e: Exception ){
println("setTunnelConfiguration FILE NullPointerException")
}
} else if (call.method == "update") {
//
} else {
result.notImplemented()
}
}
}
override fun onActivityResult(request: Int, result: Int, data: Intent?) {
if (result == RESULT_OK) {
startService(getServiceIntent())
} else {
super.onActivityResult(request, result, data)
}
}
}
@@ -0,0 +1,251 @@
package com.sail_tunnel.sail
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.net.*
import android.os.Build
import android.os.ParcelFileDescriptor
import androidx.core.app.NotificationCompat
import com.sail_tunnel.sail.net.DefaultNetworkListener
import com.sail_tunnel.sail.net.DnsResolverCompat
import com.sail_tunnel.sail.services.LocalDnsWorker
import com.sail_tunnel.sail.services.TunnelInstance
import com.sail_tunnel.sail.services.VpnState
import com.sail_tunnel.sail.utils.readableMessage
import kotlinx.coroutines.*
import java.io.File
import java.io.IOException
class TunnelService : VpnService() {
companion object {
private const val CORE_NAME = "leaf"
private const val VPN_MTU = 1500
private const val PRIVATE_VLAN4_CLIENT = "198.18.20.20"
private const val PRIVATE_VLAN4_ROUTER = "1.1.1.1"
}
inner class NullConnectionException : NullPointerException() {
override fun getLocalizedMessage() =
"Failed to start VPN service. You might need to reboot your device."
}
private val data = VpnState.Data()
private fun startRunner() {
if (Build.VERSION.SDK_INT >= 26) startForegroundService(Intent(this, javaClass))
else startService(Intent(this, javaClass))
}
private var pfd: ParcelFileDescriptor? = null
private var active = false
private var metered = false
var notification: Notification? = null
private val mResultData: Intent? = null
private val mMediaProjection: MediaProjection? = null
private val mMediaProjectionManager: MediaProjectionManager? = null
@Volatile
private var underlyingNetwork: Network? = null
set(value) {
field = value
if (active) setUnderlyingNetworks(underlyingNetworks)
}
private val underlyingNetworks
get() =
// clearing underlyingNetworks makes Android 9 consider the network to be metered
if (Build.VERSION.SDK_INT == 28 && metered) null else underlyingNetwork?.let {
arrayOf(
it
)
}
override fun onRevoke() = stopRunner()
private fun killProcesses(scope: CoroutineScope) {
data.proxy?.run {
shutdown(scope)
data.proxy = null
}
data.localDns?.shutdown(scope)
data.localDns = null
active = false
scope.launch { DefaultNetworkListener.stop(this) }
pfd?.close()
pfd = null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val data = data
if (data.state != VpnState.State.Stopped) return Service.START_NOT_STICKY
try {
data.proxy = TunnelInstance()
} catch (e: IllegalArgumentException) {
stopRunner(false, e.message)
return Service.START_NOT_STICKY
}
createNotificationChannel()
data.changeState(VpnState.State.Connecting)
data.connectingJob = GlobalScope.launch(Dispatchers.Main) {
try {
preInit()
startVpn()
data.changeState(VpnState.State.Connected)
} catch (_: CancellationException) {
// if the job was cancelled, it is canceller's responsibility to call stopRunner
} catch (exc: Throwable) {
stopRunner(false, exc.readableMessage)
} finally {
data.connectingJob = null
}
}
return START_NOT_STICKY
}
private fun createNotificationChannel() {
val CHANNEL_ID: String = "notification_id"
val builder = NotificationCompat.Builder(this.applicationContext,CHANNEL_ID) //获取一个Notification构造器
val nfIntent = Intent(this, MainActivity::class.java) //点击后跳转的界面,可以设置跳转数据
val pendingIntent: PendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.getActivity(this, 0, nfIntent, PendingIntent.FLAG_IMMUTABLE)
} else {
PendingIntent.getActivity(this, 0, nfIntent, PendingIntent.FLAG_ONE_SHOT)
}
val intentClick = Intent(
this,MainActivity::class.java
// BroadcastReceiver::class.java
)
intentClick.action = "notification_clicked"
// intentClick.putExtra(BroadcastReceiver.TYPE, type)
val pendingIntentClick =
PendingIntent.getBroadcast(this, 0, intentClick, PendingIntent.FLAG_ONE_SHOT)
//.setContentIntent(pendingIntent) // 设置PendingIntent
builder.setContentIntent(pendingIntentClick).setLargeIcon(
BitmapFactory.decodeResource(
this.resources,
R.mipmap.app_icon_round
)
) // 设置下拉列表中的图标(大图标)
.setContentTitle("UUVPN") // 设置下拉列表里的标题
.setSmallIcon( R.mipmap.app_icon_round) // 设置状态栏内的小图标
.setContentText("正在运行...") // 设置上下文内容
.setWhen(System.currentTimeMillis()) // 设置该通知发生的时间
/*以下是对Android 8.0的适配*/
//普通notification适配
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId("notification_id")
}
//前台服务notification适配
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"notification_id",
"notification_name",
NotificationManager.IMPORTANCE_LOW
)
// Register the channel with the system
val notificationManager: NotificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
notification = builder.build() // 获取构建好的Notification
// notification.defaulte = Notification.DEFAULT_SOUND //设置为默认的声音
try {
startForeground(110, notification)
} catch (w: Exception) {
w.printStackTrace()
}
}
private suspend fun preInit() = DefaultNetworkListener.start(this) { underlyingNetwork = it }
private suspend fun rawResolver(query: ByteArray) =
// no need to listen for network here as this is only used for forwarding local DNS queries.
// retries should be attempted by client.
DnsResolverCompat.resolveRaw(underlyingNetwork ?: throw IOException("no network"), query)
private suspend fun startVpn() {
val builder = Builder()
.setConfigureIntent(Core.configureIntent(this))
.setSession(CORE_NAME)
.setMtu(VPN_MTU)
.addAddress(PRIVATE_VLAN4_CLIENT, 24)
.addDnsServer(PRIVATE_VLAN4_ROUTER)
.addRoute("0.0.0.0", 0)
active = true // possible race condition here?
builder.setUnderlyingNetworks(underlyingNetworks)
if (Build.VERSION.SDK_INT >= 29) builder.setMetered(metered)
this.pfd = builder.establish() ?: throw NullConnectionException()
val context = Core.deviceStorage
val configRoot = context.noBackupFilesDir
data.localDns = LocalDnsWorker(this::rawResolver).apply { start() }
val configFile = File(configRoot, VpnState.CONFIG_FILE)
val configContent = configFile
.readText()
.replace("{{leafLogFile}}", File(configRoot, VpnState.LEAF_LOG_FILE).absolutePath)
.replace("{{tunFd}}", this.pfd?.fd?.toLong().toString())
configFile.writeText(configContent)
data.proxy!!.start(
this,
File(Core.deviceStorage.noBackupFilesDir, "stat_main"),
configFile,
)
}
private fun stopRunner(restart: Boolean = false, msg: String? = null) {
if (data.state == VpnState.State.Stopping) return
// channge the state
data.changeState(VpnState.State.Stopping)
GlobalScope.launch(Dispatchers.Main.immediate) {
data.connectingJob?.cancelAndJoin() // ensure stop connecting first
// we use a coroutineScope here to allow clean-up in parallel
coroutineScope {
killProcesses(GlobalScope)
}
// change the state
data.changeState(VpnState.State.Stopped, msg)
// stop the service if nothing has bound to it
if (restart) startRunner() else {
stopSelf()
}
}
}
}
@@ -0,0 +1,23 @@
package com.sail_tunnel.sail.net
import android.net.LocalSocket
import kotlinx.coroutines.*
import timber.log.Timber
import java.io.File
abstract class ConcurrentLocalSocketListener(name: String, socketFile: File) : LocalSocketListener(name, socketFile),
CoroutineScope {
override val coroutineContext = Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler { _, t -> Timber.w(t) }
override fun accept(socket: LocalSocket) {
launch { super.accept(socket) }
}
override fun shutdown(scope: CoroutineScope) {
running = false
cancel()
super.shutdown(scope)
coroutineContext[Job]!!.also { job -> scope.launch { job.join() } }
}
}
@@ -0,0 +1,126 @@
package com.sail_tunnel.sail.net
import android.annotation.TargetApi
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.os.Handler
import android.os.Looper
import androidx.annotation.RequiresApi
import com.sail_tunnel.sail.Core
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.runBlocking
import java.net.UnknownHostException
object DefaultNetworkListener {
private sealed class NetworkMessage {
class Start(val key: Any, val listener: (Network?) -> Unit) : NetworkMessage()
class Get : NetworkMessage() {
val response = CompletableDeferred<Network>()
}
class Stop(val key: Any) : NetworkMessage()
class Put(val network: Network) : NetworkMessage()
class Update(val network: Network) : NetworkMessage()
class Lost(val network: Network) : NetworkMessage()
}
private val networkActor = GlobalScope.actor<NetworkMessage>(Dispatchers.Unconfined) {
val listeners = mutableMapOf<Any, (Network?) -> Unit>()
var network: Network? = null
val pendingRequests = arrayListOf<NetworkMessage.Get>()
for (message in channel) when (message) {
is NetworkMessage.Start -> {
if (listeners.isEmpty()) register()
listeners[message.key] = message.listener
if (network != null) message.listener(network)
}
is NetworkMessage.Get -> {
check(listeners.isNotEmpty()) { "Getting network without any listeners is not supported" }
if (network == null) pendingRequests += message else message.response.complete(network)
}
is NetworkMessage.Stop -> if (listeners.isNotEmpty() && // was not empty
listeners.remove(message.key) != null && listeners.isEmpty()) {
network = null
unregister()
}
is NetworkMessage.Put -> {
network = message.network
pendingRequests.forEach { it.response.complete(message.network) }
pendingRequests.clear()
listeners.values.forEach { it(network) }
}
is NetworkMessage.Update -> if (network == message.network) listeners.values.forEach { it(network) }
is NetworkMessage.Lost -> if (network == message.network) {
network = null
listeners.values.forEach { it(null) }
}
}
}
suspend fun start(key: Any, listener: (Network?) -> Unit) = networkActor.send(NetworkMessage.Start(key, listener))
suspend fun get() = if (fallback) {
Core.connectivity.activeNetwork ?: throw UnknownHostException() // failed to listen, return current if available
} else NetworkMessage.Get().run {
networkActor.send(this)
response.await()
}
suspend fun stop(key: Any) = networkActor.send(NetworkMessage.Stop(key))
// NB: this runs in ConnectivityThread, and this behavior cannot be changed until API 26
private object Callback : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) = runBlocking { networkActor.send(NetworkMessage.Put(network)) }
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
// it's a good idea to refresh capabilities
runBlocking { networkActor.send(NetworkMessage.Update(network)) }
}
override fun onLost(network: Network) = runBlocking { networkActor.send(NetworkMessage.Lost(network)) }
}
private var fallback = false
private val request = NetworkRequest.Builder().apply {
addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
}.build()
private val mainHandler = Handler(Looper.getMainLooper())
/**
* Unfortunately registerDefaultNetworkCallback is going to return VPN interface since Android P DP1:
* https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
*
* This makes doing a requestNetwork with REQUEST necessary so that we don't get ALL possible networks that
* satisfies default network capabilities but only THE default network. Unfortunately, we need to have
* android.permission.CHANGE_NETWORK_STATE to be able to call requestNetwork.
*
* Source: https://android.googlesource.com/platform/frameworks/base/+/2df4c7d/services/core/java/com/android/server/ConnectivityService.java#887
*/
private fun register() {
when (Build.VERSION.SDK_INT) {
in 31..Int.MAX_VALUE -> @TargetApi(31) {
Core.connectivity.registerBestMatchingNetworkCallback(request, Callback, mainHandler)
}
in 28 until 31 -> @TargetApi(28) { // we want REQUEST here instead of LISTEN
Core.connectivity.requestNetwork(request, Callback, mainHandler)
}
in 26 until 28 -> @TargetApi(26) {
Core.connectivity.registerDefaultNetworkCallback(Callback, mainHandler)
}
in 24 until 26 -> {
Core.connectivity.registerDefaultNetworkCallback(Callback)
}
else -> try {
fallback = false
Core.connectivity.requestNetwork(request, Callback)
} catch (e: RuntimeException) {
fallback = true // known bug on API 23: https://stackoverflow.com/a/33509180/2245107
}
}
}
private fun unregister() = Core.connectivity.unregisterNetworkCallback(Callback)
}
@@ -0,0 +1,167 @@
package com.sail_tunnel.sail.net
import android.annotation.TargetApi
import android.net.DnsResolver
import android.net.Network
import android.os.Build
import android.os.CancellationSignal
import androidx.annotation.RequiresApi
import com.sail_tunnel.sail.Core
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import org.xbill.DNS.*
import java.io.IOException
import java.net.Inet4Address
import java.net.Inet6Address
import java.net.InetAddress
import java.util.concurrent.Executor
import java.util.concurrent.Executors
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
sealed class DnsResolverCompat {
companion object : DnsResolverCompat() {
private val instance by lazy {
when (Build.VERSION.SDK_INT) {
in 29..Int.MAX_VALUE -> DnsResolverCompat29
in 23 until 29 -> DnsResolverCompat23
else -> error("Unsupported API level")
}
}
override suspend fun resolve(network: Network, host: String) = instance.resolve(network, host)
override suspend fun resolveOnActiveNetwork(host: String) = instance.resolveOnActiveNetwork(host)
override suspend fun resolveRaw(network: Network, query: ByteArray) = instance.resolveRaw(network, query)
override suspend fun resolveRawOnActiveNetwork(query: ByteArray) = instance.resolveRawOnActiveNetwork(query)
// additional platform-independent DNS helpers
/**
* TTL returned from localResolver is set to 120. Android API does not provide TTL,
* so we suppose Android apps should not care about TTL either.
*/
private const val TTL = 120L
fun prepareDnsResponse(request: Message) = Message(request.header.id).apply {
header.setFlag(Flags.QR.toInt()) // this is a response
header.setFlag(Flags.RA.toInt()) // recursion available
if (request.header.getFlag(Flags.RD.toInt())) header.setFlag(Flags.RD.toInt())
request.question?.also { addRecord(it, Section.QUESTION) }
}
}
abstract suspend fun resolve(network: Network, host: String): Array<InetAddress>
abstract suspend fun resolveOnActiveNetwork(host: String): Array<InetAddress>
abstract suspend fun resolveRaw(network: Network, query: ByteArray): ByteArray
abstract suspend fun resolveRawOnActiveNetwork(query: ByteArray): ByteArray
private object DnsResolverCompat23 : DnsResolverCompat() {
/**
* This dispatcher is used for noncancellable possibly-forever-blocking operations in network IO.
*
* See also: https://issuetracker.google.com/issues/133874590
*/
private val unboundedIO by lazy {
if (Core.activity.isLowRamDevice) Dispatchers.IO
else Executors.newCachedThreadPool().asCoroutineDispatcher()
}
override suspend fun resolve(network: Network, host: String) =
withContext(unboundedIO) { network.getAllByName(host) }
override suspend fun resolveOnActiveNetwork(host: String) =
withContext(unboundedIO) { InetAddress.getAllByName(host) }
private suspend fun resolveRaw(query: ByteArray, networkSpecified: Boolean = true,
hostResolver: suspend (String) -> Array<InetAddress>): ByteArray {
val request = try {
Message(query)
} catch (e: IOException) {
throw UnsupportedOperationException(e) // unrecognized packet
}
when (val opcode = request.header.opcode) {
Opcode.QUERY -> { }
else -> throw UnsupportedOperationException("Unsupported opcode $opcode")
}
val question = request.question
val isIpv6 = when (val type = question?.type) {
Type.A -> false
Type.AAAA -> true
Type.PTR -> {
/* Android does not provide a PTR lookup API for Network prior to Android 10 */
if (networkSpecified) throw IOException(UnsupportedOperationException("Network unspecified"))
val ip = try {
ReverseMap.fromName(question.name)
} catch (e: IOException) {
throw UnsupportedOperationException(e) // unrecognized PTR name
}
val hostname = withContext(unboundedIO) { ip.hostName }.let { hostname ->
if (hostname == ip.hostAddress) null else Name.fromString("$hostname.")
}
return prepareDnsResponse(request).apply {
hostname?.let { addRecord(PTRRecord(question.name, DClass.IN, TTL, it), Section.ANSWER) }
}.toWire()
}
else -> throw UnsupportedOperationException("Unsupported query type $type")
}
val host = question.name.canonicalize().toString(true)
return prepareDnsResponse(request).apply {
for (address in hostResolver(host).asIterable().run {
if (isIpv6) filterIsInstance<Inet6Address>() else filterIsInstance<Inet4Address>()
}) addRecord(when (address) {
is Inet4Address -> ARecord(question.name, DClass.IN, TTL, address)
is Inet6Address -> AAAARecord(question.name, DClass.IN, TTL, address)
else -> error("Unsupported address $address")
}, Section.ANSWER)
}.toWire()
}
override suspend fun resolveRaw(network: Network, query: ByteArray) =
resolveRaw(query) { resolve(network, it) }
override suspend fun resolveRawOnActiveNetwork(query: ByteArray) =
resolveRaw(query, false, this::resolveOnActiveNetwork)
}
@TargetApi(29)
private object DnsResolverCompat29 : DnsResolverCompat(), Executor {
/**
* This executor will run on its caller directly. On Q beta 3 thru 4, this results in calling in main thread.
*/
override fun execute(command: Runnable) = command.run()
private val activeNetwork get() = Core.connectivity.activeNetwork ?: throw IOException("no network")
override suspend fun resolve(network: Network, host: String): Array<InetAddress> {
return suspendCancellableCoroutine { cont ->
val signal = CancellationSignal()
cont.invokeOnCancellation { signal.cancel() }
// retry should be handled by client instead
DnsResolver.getInstance().query(network, host, DnsResolver.FLAG_NO_RETRY, this,
signal, object : DnsResolver.Callback<Collection<InetAddress>> {
override fun onAnswer(answer: Collection<InetAddress>, rcode: Int) =
cont.resume(answer.toTypedArray())
override fun onError(error: DnsResolver.DnsException) = cont.resumeWithException(
IOException(error)
)
})
}
}
override suspend fun resolveOnActiveNetwork(host: String) = resolve(activeNetwork, host)
override suspend fun resolveRaw(network: Network, query: ByteArray): ByteArray {
return suspendCancellableCoroutine { cont ->
val signal = CancellationSignal()
cont.invokeOnCancellation { signal.cancel() }
DnsResolver.getInstance().rawQuery(network, query, DnsResolver.FLAG_NO_RETRY, this,
signal, object : DnsResolver.Callback<ByteArray> {
override fun onAnswer(answer: ByteArray, rcode: Int) = cont.resume(answer)
override fun onError(error: DnsResolver.DnsException) = cont.resumeWithException(
IOException(error)
)
})
}
}
override suspend fun resolveRawOnActiveNetwork(query: ByteArray) = resolveRaw(activeNetwork, query)
}
}
@@ -0,0 +1,62 @@
package com.sail_tunnel.sail.net
import android.annotation.SuppressLint
import android.net.LocalServerSocket
import android.net.LocalSocket
import android.net.LocalSocketAddress
import android.system.ErrnoException
import android.system.Os
import android.system.OsConstants
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.onFailure
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File
import java.io.IOException
abstract class LocalSocketListener(name: String, socketFile: File) : Thread(name) {
private val localSocket = LocalSocket().apply {
socketFile.delete() // It's a must-have to close and reuse previous local socket.
bind(LocalSocketAddress(socketFile.absolutePath, LocalSocketAddress.Namespace.FILESYSTEM))
}
private val serverSocket = LocalServerSocket(localSocket.fileDescriptor)
private val closeChannel = Channel<Unit>(1)
@Volatile
protected var running = true
/**
* Inherited class do not need to close input/output streams as they will be closed automatically.
*/
protected open fun accept(socket: LocalSocket) = socket.use { acceptInternal(socket) }
protected abstract fun acceptInternal(socket: LocalSocket)
final override fun run() {
localSocket.use {
while (running) {
try {
accept(serverSocket.accept())
} catch (e: IOException) {
if (running) Timber.w(e)
continue
}
}
}
closeChannel.trySendBlocking(Unit).onFailure { throw it!! }
}
@SuppressLint("NewApi")
open fun shutdown(scope: CoroutineScope) {
running = false
localSocket.fileDescriptor?.apply {
// see also: https://issuetracker.google.com/issues/36945762#comment15
if (valid()) try {
Os.shutdown(this, OsConstants.SHUT_RDWR)
} catch (e: ErrnoException) {
// suppress fd inactive or already closed
if (e.errno != OsConstants.EBADF && e.errno != OsConstants.ENOTCONN) throw e.rethrowAsSocketException()
}
}
scope.launch { closeChannel.receive() }
}
}
@@ -0,0 +1,64 @@
package com.sail_tunnel.sail.services
import android.net.LocalSocket
import android.os.Build
import androidx.annotation.RequiresApi
import com.sail_tunnel.sail.Core
import com.sail_tunnel.sail.net.ConcurrentLocalSocketListener
import com.sail_tunnel.sail.net.DnsResolverCompat
import com.sail_tunnel.sail.utils.readableMessage
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.DataInputStream
import java.io.DataOutputStream
import java.io.File
import java.io.IOException
import org.xbill.DNS.Message
import org.xbill.DNS.Rcode
class LocalDnsWorker(private val resolver: suspend (ByteArray) -> ByteArray) : ConcurrentLocalSocketListener(
"LocalDnsThread", File(Core.deviceStorage.noBackupFilesDir, "local_dns_path")
), CoroutineScope {
override fun acceptInternal(socket: LocalSocket) = error("big no no")
override fun accept(socket: LocalSocket) {
launch {
socket.use {
val input = DataInputStream(socket.inputStream)
val query = try {
ByteArray(input.readUnsignedShort()).also { input.read(it) }
} catch (e: IOException) { // connection early close possibly due to resolving timeout
return@use Timber.d(e)
}
try {
resolver(query)
} catch (e: Exception) {
when (e) {
is TimeoutCancellationException -> Timber.w("Resolving timed out")
is CancellationException -> { } // ignore
is IOException -> Timber.d(e)
is UnsupportedOperationException -> Timber.w(e.message)
else -> Timber.w(e)
}
try {
DnsResolverCompat.prepareDnsResponse(Message(query)).apply {
header.rcode = Rcode.SERVFAIL
}.toWire()
} catch (_: IOException) {
byteArrayOf() // return empty if cannot parse packet
}
}.let { response ->
try {
val output = DataOutputStream(socket.outputStream)
output.writeShort(response.size)
output.write(response)
} catch (e: IOException) {
Timber.d(e.readableMessage)
}
}
}
}
}
}
@@ -0,0 +1,89 @@
package com.sail_tunnel.sail.services
import android.net.LocalSocket
import android.os.SystemClock
import com.sail_tunnel.sail.net.LocalSocketListener
import com.sail_tunnel.sail.utils.TrafficStats
import java.io.File
import java.io.IOException
import java.nio.ByteBuffer
import java.nio.ByteOrder
class TrafficMonitor(statFile: File) {
val thread = object : LocalSocketListener("TrafficMonitor-" + statFile.name, statFile) {
private val buffer = ByteArray(16)
private val stat = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN)
override fun acceptInternal(socket: LocalSocket) {
when (val read = socket.inputStream.read(buffer)) {
-1 -> return
16 -> { }
else -> throw IOException("Unexpected traffic stat length $read")
}
val tx = stat.getLong(0)
val rx = stat.getLong(8)
if (current.txTotal != tx) {
current.txTotal = tx
dirty = true
}
if (current.rxTotal != rx) {
current.rxTotal = rx
dirty = true
}
}
}.apply { start() }
val current = TrafficStats()
var out = TrafficStats()
private var timestampLast = 0L
private var dirty = false
private var persisted: TrafficStats? = null
fun requestUpdate(): Pair<TrafficStats, Boolean> {
val now = SystemClock.elapsedRealtime()
val delta = now - timestampLast
timestampLast = now
var updated = false
if (delta != 0L) {
if (dirty) {
out = current.copy().apply {
txRate = (txTotal - out.txTotal) * 1024 / delta
rxRate = (rxTotal - out.rxTotal) * 1024 / delta
}
dirty = false
updated = true
} else {
if (out.txRate != 0L) {
out.txRate = 0
updated = true
}
if (out.rxRate != 0L) {
out.rxRate = 0
updated = true
}
}
}
return Pair(out, updated)
}
fun persistStats() {
val current = current
check(persisted == null || persisted == current) { "Data loss occurred" }
persisted = current
// try {
// // profile may have host, etc. modified and thus a re-fetch is necessary (possible race condition)
// val profile = ProfileManager.getProfile(id) ?: return
// profile.tx += current.txTotal
// profile.rx += current.rxTotal
// ProfileManager.updateProfile(profile)
// } catch (e: IOException) {
// if (!DataStore.directBootAware) throw e // we should only reach here because we're in direct boot
// val profile = DirectBoot.getDeviceProfile()!!.toList().single { it.id == id }
// profile.tx += current.txTotal
// profile.rx += current.rxTotal
// profile.dirty = true
// DirectBoot.update(profile)
// DirectBoot.listenForUnlock()
// }
}
}
@@ -0,0 +1,106 @@
package com.sail_tunnel.sail.services
import android.net.LocalServerSocket
import android.net.LocalSocket
import android.net.LocalSocketAddress
import android.system.Os
import com.sail_tunnel.sail.Core
import com.sail_tunnel.sail.TunnelService
import kotlinx.coroutines.CoroutineScope
import timber.log.Timber
import java.io.File
import java.nio.ByteBuffer
import kotlin.concurrent.thread
class TunnelInstance() {
private var configFile: File? = null
var trafficMonitor: TrafficMonitor? = null
private val rtId: Int = 666
init {
System.loadLibrary("leaf")
}
private external fun leafRun(rtId: Int, configPath: String)
private external fun leafReload(rtId: Int)
private external fun leafShutdown(rtId: Int)
private external fun leafTestConfig(configPath: String)
/**
* Sensitive shadowsocks configuration file requires extra protection. It may be stored in encrypted storage or
* device storage, depending on which is currently available.
*/
fun start(
service: TunnelService,
stat: File,
configFile: File,
) {
// setup traffic monitor path
trafficMonitor = TrafficMonitor(stat)
Timber.i("start process")
val context = Core.deviceStorage
val configRoot = context.noBackupFilesDir //noBackupFilesDir
val protectPath =
File.createTempFile("socket_protect", ".sock", configRoot).absolutePath
Os.setenv("SOCKET_PROTECT_PATH", protectPath, true)
println("protectPath: $protectPath")
thread (start = true) {
val localSocket = LocalSocket()
localSocket.bind(
LocalSocketAddress(
protectPath,
LocalSocketAddress.Namespace.FILESYSTEM
)
)
val socket = LocalServerSocket(localSocket.fileDescriptor)
val buffer = ByteBuffer.allocate(4)
while (true) {
val stream = socket.accept()
buffer.clear()
val n = stream.inputStream.read(buffer.array())
System.out.write(n)
if (n == 4) {
val fd = buffer.int
if (!service.protect(fd)) {
println("protect failed")
}
buffer.clear()
buffer.putInt(0)
} else {
buffer.clear()
buffer.putInt(1)
}
stream.outputStream.write(buffer.array())
}
}
// start tunnel program
thread(start = true) {
leafRun(rtId, configFile.absolutePath)
}
}
fun shutdown(scope: CoroutineScope) {
trafficMonitor?.apply {
thread.shutdown(scope)
persistStats() // Make sure update total traffic when stopping the runner
}
trafficMonitor = null
configFile?.delete() // remove old config possibly in device storage
configFile = null
// stop tunnel program
thread(start = true, isDaemon = true) {
leafShutdown(rtId)
}
}
}
@@ -0,0 +1,32 @@
package com.sail_tunnel.sail.services
import kotlinx.coroutines.Job
object VpnState {
enum class State {
/**
* Idle state is only used by UI and will never be returned by BaseService.
*/
Idle,
Connecting,
Connected,
Stopping,
Stopped,
}
const val CONFIG_FILE = "leaf.conf"
const val LEAF_LOG_FILE = "leaf.log"
class Data internal constructor() {
var state = State.Stopped
var proxy: TunnelInstance? = null
var localDns: LocalDnsWorker? = null
var connectingJob: Job? = null
fun changeState(s: State, msg: String? = null) {
if (state == s && msg == null) return
state = s
}
}
}
@@ -0,0 +1,18 @@
package com.sail_tunnel.sail.utils
import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
@SuppressLint("Registered")
class DeviceStorageApp(context: Context) : Application() {
init {
attachBaseContext(context.createDeviceProtectedStorageContext())
}
/**
* Thou shalt not get the REAL underlying application context which would no longer be operating under device
* protected storage.
*/
override fun getApplicationContext() = this
}
@@ -0,0 +1,20 @@
package com.sail_tunnel.sail.utils
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
data class TrafficStats(
// Bytes per second
var txRate: Long = 0L,
var rxRate: Long = 0L,
// Bytes for the current session
var txTotal: Long = 0L,
var rxTotal: Long = 0L
) : Parcelable {
operator fun plus(other: TrafficStats) = TrafficStats(
txRate + other.txRate, rxRate + other.rxRate,
txTotal + other.txTotal, rxTotal + other.rxTotal
)
}
@@ -0,0 +1,33 @@
package com.sail_tunnel.sail.utils
import android.annotation.SuppressLint
import android.os.Build
import kotlinx.coroutines.*
import java.io.FileDescriptor
import java.net.HttpURLConnection
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
val Throwable.readableMessage: String get() = localizedMessage ?: javaClass.name
/**
* https://android.googlesource.com/platform/prebuilts/runtime/+/94fec32/appcompat/hiddenapi-light-greylist.txt#9466
*/
@SuppressLint("DiscouragedPrivateApi")
private val getInt = FileDescriptor::class.java.getDeclaredMethod("getInt$")
val FileDescriptor.int get() = getInt.invoke(this) as Int
suspend fun <T> HttpURLConnection.useCancellable(block: suspend HttpURLConnection.() -> T): T {
return suspendCancellableCoroutine { cont ->
cont.invokeOnCancellation {
if (Build.VERSION.SDK_INT >= 26) disconnect() else GlobalScope.launch(Dispatchers.IO) { disconnect() }
}
GlobalScope.launch(Dispatchers.IO) {
try {
cont.resume(block())
} catch (e: Throwable) {
cont.resumeWithException(e)
}
}
}
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
@@ -0,0 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sail_tunnel.sail">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
</manifest>
+31
View File
@@ -0,0 +1,31 @@
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
+4
View File
@@ -0,0 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.suppressUnsupportedCompileSdk=33
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
+11
View File
@@ -0,0 +1,11 @@
include ':app'
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 36 17.2" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="-15.5" x2="59.992" y1="10" y2="75.024" gradientTransform="matrix(1.056419, 0, 0, 1, -59.971069, -0.317375)">
<stop offset="0" stop-color="#62c"/>
<stop offset="1" stop-color="#301060"/>
</linearGradient>
<g fill="url(#a)" transform="matrix(1, 0, 0, 1, -1.853645, -1.351658)">
<path d="M 27.827 3.42 C 27.585 3.297 27.307 3.264 27.043 3.327 C 26.77 3.396 26.527 3.551 26.349 3.771 L 24.595 5.858 L 21.485 2.156 C 21.231 1.853 20.885 1.683 20.526 1.683 C 20.166 1.683 19.821 1.853 19.567 2.156 L 16.457 5.858 L 14.703 3.771 C 14.526 3.552 14.282 3.397 14.009 3.329 C 13.745 3.266 13.468 3.299 13.225 3.421 C 12.977 3.543 12.765 3.75 12.616 4.015 C 12.465 4.289 12.387 4.598 12.388 4.912 L 12.388 13.459 C 12.388 14.529 12.746 15.555 13.382 16.312 C 14.018 17.069 14.88 17.494 15.779 17.496 L 25.273 17.496 C 26.173 17.494 27.034 17.069 27.67 16.312 C 28.306 15.555 28.663 14.529 28.664 13.459 L 28.664 4.912 C 28.664 4.592 28.585 4.281 28.436 4.015 C 28.298 3.759 28.086 3.552 27.827 3.42 L 27.827 3.42 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="22" fill="none" viewBox="0 0 20 22">
<path fill="#AE77FF" d="M16.64 9.39a2.112 2.112 0 00-1.925 1.25h-.97L12.69 7.478a.859.859 0 00-1.64.035l-1.454 5.086L7.721 1.593a.86.86 0 00-1.68-.067L3.704 10.64H1.25v1.718h3.125a.86.86 0 00.834-.65l1.498-5.99 1.82 10.688a.86.86 0 00.8.718h.048a.86.86 0 00.826-.625l1.737-5.845.372 1.118a.859.859 0 00.815.586h1.59a2.11 2.11 0 101.926-2.968z"/>
</svg>

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 900 600"><path fill="#EE1C25" d="M0 0h900v600H0z"/><g id="a"><path d="M449.964 299.913c-105.263-44.486-58.602-181.581 42.07-174.69-20.366 10.467-23.318 29.997-11.687 48.09 13.024 20.256-1.2 52.848-18.806 60.767-28.935 13.025-34.728 47.75-11.577 65.833z" fill="#fff"/><path d="M444.272 200.92l-5.92 9.294-2.144-10.815-10.679-2.759 9.625-5.39-.671-10.999 8.085 7.49 10.256-4.043-4.61 10.01 7.001 8.505zm6.288 97.839c-12.731-6.534-22.996-20.155-27.468-36.431-5.115-18.67-2.173-38.743 8.083-55.038l-2.208-1.394c-10.64 16.929-13.693 37.743-8.386 57.12 4.728 17.221 15.214 31.097 28.787 38.064z" fill="#EE1C25"/></g><use xlink:href="#a" transform="rotate(72 450 300)"/><use xlink:href="#a" transform="rotate(144 450 300)"/><use xlink:href="#a" transform="rotate(216 450 300)"/><use xlink:href="#a" transform="rotate(288 450 300)"/></svg>

After

Width:  |  Height:  |  Size: 927 B

+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 900 600" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h900v600h-900z" fill="#fff"/><circle cx="450" cy="300" fill="#bc002d" r="180"/></svg>

After

Width:  |  Height:  |  Size: 160 B

+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 900 600" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="m0 0h900v600h-900z" fill="#fe0000"/><path d="m0 0h450v300h-450z" fill="#000095"/></g><g fill="#fff"><path d="m225 37.5-56.25 209.928 153.678-153.678-209.928 56.25 209.928 56.25-153.678-153.678 56.25 209.928 56.25-209.928-153.678 153.678 209.928-56.25-209.928-56.25 153.678 153.678z"/><circle cx="225" cy="150" r="60" stroke="#000095" stroke-width="7.5"/></g></svg>

After

Width:  |  Height:  |  Size: 458 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 7410 3900"><path fill="#b22234" d="M0 0h7410v3900H0z"/><path d="M0 450h7410m0 600H0m0 600h7410m0 600H0m0 600h7410m0 600H0" stroke="#fff" stroke-width="300"/><path fill="#3c3b6e" d="M0 0h2964v2100H0z"/><g fill="#fff"><g id="d"><g id="c"><g id="e"><g id="b"><path id="a" d="M247 90l70.534 217.082-184.66-134.164h228.253L176.466 307.082z"/><use xlink:href="#a" y="420"/><use xlink:href="#a" y="840"/><use xlink:href="#a" y="1260"/></g><use xlink:href="#a" y="1680"/></g><use xlink:href="#b" x="247" y="210"/></g><use xlink:href="#c" x="494"/></g><use xlink:href="#d" x="988"/><use xlink:href="#c" x="1976"/><use xlink:href="#e" x="2470"/></g></svg>

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.
+1
View File
@@ -0,0 +1 @@
<svg fill="none" height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h20v20h-20z"/></clipPath><g clip-path="url(#a)" fill="#ae77ff"><path d="m10 5a.833.833 0 0 0 -.833.833v4.167c0 .221.088.433.244.59l2.5 2.5a.833.833 0 0 0 1.178-1.18l-2.256-2.255v-3.822a.833.833 0 0 0 -.833-.833z"/><path d="m19.844 8.443a10 10 0 0 0 -16.862-5.597v-2.013a.833.833 0 0 0 -1.667 0v3.334a1.667 1.667 0 0 0 1.667 1.666h3.333a.833.833 0 1 0 0-1.666h-2.292a8.325 8.325 0 1 1 -2.363 6.565.818.818 0 0 0 -.826-.732.839.839 0 0 0 -.834.917 10 10 0 1 0 19.84-2.474z"/></g></svg>

After

Width:  |  Height:  |  Size: 651 B

+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="none" viewBox="0 0 22 22">
<path fill="#B5AEBE" d="M21.484 9.6l-7.79-8.422a3.667 3.667 0 00-5.385 0L.533 9.597A1.833 1.833 0 000 10.889v8.347a2.75 2.75 0 002.75 2.75h3.667v-5.5a4.57 4.57 0 012.409-4.01l.139-.075a4.55 4.55 0 01.528-.223c.124-.045.25-.084.379-.117.129-.034.285-.065.431-.092.081-.013.156-.04.239-.049a4.53 4.53 0 01.417-.017c.014 0 .027-.005.041-.005h.017c.283.002.566.031.845.086.03.006.062.009.091.015.262.057.517.137.765.239.035.013.07.026.104.042.237.102.465.225.68.366l.102.068c.21.146.407.309.59.487l.085.086c.179.184.343.382.49.592l.062.092c.144.219.27.45.375.69l.034.092c.104.253.186.515.243.784 0 .02.007.04.01.061.06.292.09.59.09.888v5.5h3.667a2.75 2.75 0 002.75-2.75v-8.36c0-.477-.185-.934-.516-1.277z"/>
<path fill="#B5AEBE" d="M11 13.736a2.75 2.75 0 00-2.75 2.75v5.5h5.5v-5.5a2.75 2.75 0 00-2.75-2.75z"/>
</svg>

After

Width:  |  Height:  |  Size: 913 B

+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="15" fill="none" viewBox="0 0 17 15">
<path fill="#AE77FF" d="M3.727 15H.309V.781h3.418V15zm1.982 0V.781h4.58c1.257 0 2.386.287 3.39.86a5.934 5.934 0 012.343 2.412c.566 1.035.853 2.197.86 3.486v.654c0 1.302-.277 2.471-.83 3.506a6.03 6.03 0 01-2.325 2.422c-.996.58-2.11.872-3.34.879H5.71zM9.137 3.428v8.935h1.191c.984 0 1.739-.348 2.266-1.045.527-.703.791-1.744.791-3.125v-.615c0-1.374-.264-2.409-.79-3.105-.528-.697-1.296-1.045-2.306-1.045H9.138z"/>
</svg>

After

Width:  |  Height:  |  Size: 517 B

+1
View File
@@ -0,0 +1 @@
<svg fill="none" height="56" viewBox="0 0 56 56" width="56" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="-4.2" x2="36.4" y1="-22.4" y2="99.4"><stop offset="0" stop-color="#62c"/><stop offset="1" stop-color="#0b0415"/></linearGradient><path clip-rule="evenodd" d="m50.423 5.823a3.865 3.865 0 0 1 2.698.329c.852.433 1.58 1.166 2.093 2.107a6.67 6.67 0 0 1 .786 3.177v30.268c-.004 3.79-1.234 7.424-3.421 10.104s-5.153 4.188-8.246 4.192h-32.666c-3.093-.005-6.059-1.512-8.246-4.192s-3.417-6.314-3.421-10.104v-30.268c0-1.131.274-2.236.787-3.177.513-.939 1.241-1.673 2.093-2.105a3.876 3.876 0 0 1 2.696-.326c.905.22 1.736.765 2.389 1.565l6.035 7.394 10.7-13.113c.877-1.072 2.064-1.674 3.3-1.674 1.237 0 2.424.602 3.3 1.674l10.7 13.113 6.034-7.394c.652-.802 1.483-1.349 2.39-1.57zm-22.42 15.18c5.95.07 10.86 4.515 11.684 10.285.072.538.107 1.111.107 1.685 0 .573-.035 1.183-.107 1.756-.789 5.268-5.018 9.426-10.358 10.071h-10.967v-18.637h3.44v15.232h7.276c3.548-.537 6.38-3.225 7.097-6.666a7.363 7.363 0 0 0 .215-1.756c0-.574-.072-1.147-.18-1.685a8.589 8.589 0 0 0 -3.225-5.125c-1.326-1.003-2.975-1.613-4.767-1.72h-9.856v-3.44h9.64z" fill="url(#a)" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 16.3 15.8" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="-15.5" x2="59.992" y1="10" y2="75.024" gradientTransform="matrix(1.056419, 0, 0, 1, -60.033002, -0.422793)">
<stop offset="0" stop-color="#62c"/>
<stop offset="1" stop-color="#301060"/>
</linearGradient>
<g fill="url(#a)" transform="matrix(1, 0, 0, 1, -12.325989, -1.578)">
<path d="M 27.765 3.315 C 27.523 3.192 20.823 1.578 20.464 1.578 C 20.104 1.578 13.406 3.194 13.163 3.316 C 12.915 3.438 12.703 3.645 12.554 3.91 C 12.403 4.184 12.325 4.493 12.326 4.807 L 12.326 13.354 C 12.326 14.424 12.684 15.45 13.32 16.207 C 13.956 16.964 14.818 17.389 15.717 17.391 L 25.211 17.391 C 26.111 17.389 26.972 16.964 27.608 16.207 C 28.244 15.45 28.601 14.424 28.602 13.354 L 28.602 4.807 C 28.602 4.487 28.523 4.176 28.374 3.91 C 28.236 3.654 28.024 3.447 27.765 3.315 Z"/>
</g>
<path d="M 12.276 0.128 L 12.956 0.128 L 12.956 7.651 L 12.218 7.651 L 8.427 1.317 L 8.427 7.651 L 7.712 7.651 L 7.712 0.128 L 8.509 0.128 L 12.276 6.368 Z" transform="matrix(1.86918, 0, 0, 0.767696, -11.240033, 5.053573)" style="fill: rgb(27, 27, 27); paint-order: fill; white-space: pre;"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 179 KiB

+1
View File
@@ -0,0 +1 @@
<svg fill="none" height="48" viewBox="0 0 46 48" width="46" xmlns="http://www.w3.org/2000/svg"><g fill="#ae77ff"><path d="m13.01 7.857c-.613-1.062-1.979-1.435-2.974-.719a22.2 22.2 0 1 0 25.928 0c-.995-.716-2.361-.343-2.974.719s-.239 2.409.738 3.15a17.76 17.76 0 1 1 -21.456 0c.977-.741 1.351-2.088.738-3.15z"/><rect height="14.8" rx="2.22" width="4.44" x="20.78"/></g></svg>

After

Width:  |  Height:  |  Size: 374 B

+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="24" fill="none" viewBox="0 0 22 24">
<path fill="#B5AEBE" stroke="#B5AEBE" stroke-width="2" d="M1 13.75c0-1.514 1.165-2.771 2.671-2.918l.586.697c3.51 4.178 9.976 4.178 13.486 0l.586-.697C19.835 10.978 21 12.236 21 13.75v3.16c0 3.355-2.746 6.09-6.15 6.09h-7.7C3.746 23 1 20.265 1 16.91v-3.16zm14.5-8.295c0 2.452-2.007 4.454-4.5 4.454S6.5 7.907 6.5 5.455C6.5 3.002 8.507 1 11 1s4.5 2.002 4.5 4.455z"/>
</svg>

After

Width:  |  Height:  |  Size: 468 B

+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" fill="none" viewBox="0 0 21 21">
<path fill="#AE77FF" d="M18.406 10.58v-1.1l1.38-1.207a1.438 1.438 0 00.273-1.833l-1.696-2.875a1.438 1.438 0 00-1.243-.718 1.438 1.438 0 00-.46.071l-1.747.59c-.301-.2-.616-.38-.941-.54l-.367-1.81A1.437 1.437 0 0012.167 0H8.805a1.437 1.437 0 00-1.438 1.157L7 2.97a8.252 8.252 0 00-.949.539l-1.71-.618a1.438 1.438 0 00-.46-.043 1.438 1.438 0 00-1.244.718L.94 6.44a1.438 1.438 0 00.294 1.804l1.359 1.244v1.1l-1.359 1.207a1.437 1.437 0 00-.294 1.833l1.696 2.875a1.438 1.438 0 001.243.718c.157.002.312-.023.46-.071l1.747-.59c.301.2.616.38.941.54l.367 1.81a1.438 1.438 0 001.438 1.158h3.392a1.438 1.438 0 001.438-1.157l.366-1.812c.328-.158.645-.338.949-.539l1.74.59c.148.048.303.073.46.072a1.437 1.437 0 001.243-.72l1.638-2.874a1.437 1.437 0 00-.294-1.804l-1.359-1.244zm-1.286 5.204l-2.466-.834a6.369 6.369 0 01-1.947 1.129l-.51 2.58H8.803l-.51-2.551a6.73 6.73 0 01-1.941-1.129l-2.473.805-1.696-2.875 1.955-1.725a6.397 6.397 0 010-2.25L2.184 7.16 3.88 4.284l2.466.834a6.368 6.368 0 011.947-1.129l.51-2.58h3.393l.51 2.552a6.727 6.727 0 011.941 1.128l2.473-.805 1.696 2.875-1.955 1.725a6.397 6.397 0 010 2.25l1.955 1.775-1.696 2.875z"/>
<path fill="#AE77FF" d="M10.5 14.347a4.312 4.312 0 114.313-4.313 4.268 4.268 0 01-4.313 4.313zm0-7.188a2.81 2.81 0 00-2.875 2.875 2.81 2.81 0 002.875 2.875 2.808 2.808 0 002.875-2.875A2.809 2.809 0 0010.5 7.159z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 82 18" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(0.012366, 0, 0, -0.010371, -37.907673, 26.353985)" id="g10" style="">
<g transform="scale(0.1)" id="g12">
<g transform="matrix(1.4411, 0, 0, 1.4411, 32303.105469, 1475.181641)" id="g2248">
<path id="path2250" style="fill-opacity: 1; fill-rule: nonzero; stroke: none;" d="m 13914.7,14060.9 v -3973.1 c 0,-568.29 -21.3,-974.93 -63.7,-1219.88 -42.4,-244.95 -168.2,-451.6 -377.2,-619.73 -209,-168.28 -519.3,-252.31 -930.8,-252.31 -405,0 -724.3,88.96 -957.8,267.02 -233.6,177.99 -381.4,413.99 -443.4,707.93 -1.8,9.44 -3.6,19.64 -5.4,30.19 -32.3,194.78 -48.4,584.68 -48.4,1170.08 v 1354.4 l 91.6,255 552.6,1539.1 264.4,736.5 132.2,368.2 c 22.2,61.3 43.7,122.9 66.8,183.8 23.4,60.9 47.6,121.5 66.5,184 l 111,375.8 c 36.3,125.6 73.3,250.8 109,376.6 72.2,251.2 143.2,502.8 211.2,755.5 -108.4,-238.2 -213.6,-477.6 -317.7,-717.3 -52.4,-119.7 -103.6,-239.9 -155.4,-359.9 l -153.5,-360.6 c -25.1,-60.2 -45,-122.3 -65.8,-184.2 -20.8,-61.8 -43.5,-122.9 -65.3,-184.3 l -132.2,-368.2 -264.5,-736.5 -359.3,-1000.9 -91.6,-255 -606.7,-1689.7 L 9768.62,8458.65 9423.54,7497.72 9177.2,6811.58 8894.71,6024.89 8784.1,5648.93 c -36.43,-125.46 -73.28,-250.78 -109.16,-376.44 -36.22,-125.6 -71.95,-251.34 -107.55,-377.08 l -52.74,-188.95 -26.3,-94.44 -25.88,-94.65 40.31,89.44 39.77,89.66 79.45,179.3 c 52.6,119.7 104.99,239.4 156.89,359.31 52.26,119.84 103.53,239.96 155.3,359.93 l 153.77,360.49 323.85,901.88 204.98,570.95 252.66,703.56 c 74.73,-178.89 180.45,-352.44 317.05,-520.57 72.2,-88.83 153.6,-171.82 244.1,-248.98 167.5,-142.74 366.1,-265.49 596.2,-368.33 354.3,-158.35 874.4,-237.59 1560.3,-237.59 568.2,0 1028.8,72.72 1381.5,218.02 352.7,145.31 634.4,340.51 845.1,585.46 210.7,244.95 355.2,545.34 433.6,901.39 78.4,355.98 117.6,965.09 117.6,1827.31 v 3772.3 h -1450.2"/>
</g>
<g transform="scale(1.4411)" id="g2252">
<path id="path2254" style="fill-opacity: 1; fill-rule: nonzero; stroke: none;" d="M 31195.072 9019.019 L 32037.612 11365.629 L 32077.242 11475.929 L 32168.832 11730.929 L 33095.322 14311.229 L 33359.722 15047.729 L 33361.522 15052.529 L 33492.022 15415.929 C 33514.122 15477.229 33535.522 15538.829 33558.822 15599.729 C 33582.122 15660.629 33606.322 15721.229 33625.222 15783.729 L 33736.222 16159.529 C 33772.422 16285.129 33809.422 16410.329 33845.222 16536.129 C 33917.322 16787.329 33988.422 17038.929 34056.322 17291.629 C 33948.122 17053.429 33842.822 16814.029 33738.722 16574.329 C 33686.322 16454.629 33635.122 16334.429 33583.322 16214.429 L 33429.822 15853.829 C 33404.722 15793.629 33384.822 15731.529 33364.022 15669.629 C 33343.222 15607.829 33320.622 15546.729 33298.622 15485.329 L 33166.522 15117.129 L 33143.322 15052.529 L 32168.832 15052.529 L 32077.242 15052.529 L 32077.242 12083.629 L 31844.362 11435.029 L 30967.392 8992.719 C 30912.712 8989.319 30855.952 8987.509 30797.042 8987.509 C 30392.072 8987.509 30072.802 9076.469 29839.302 9254.529 C 29605.732 9432.519 29457.932 9668.519 29395.892 9962.459 C 29359.962 10145.309 29342.062 10545.409 29342.062 11162.729 L 29342.062 15052.529 L 27891.932 15052.529 L 27891.932 11221.529 C 27891.932 10418.009 27939.242 9810.559 28033.982 9399.069 C 28099.292 9121.369 28234.852 8856.019 28440.622 8602.949 C 28646.382 8349.809 28926.402 8144.059 29280.822 7985.639 C 29578.112 7852.759 29992.102 7775.659 30522.742 7754.219 L 30257.802 7016.519 L 30147.192 6640.559 C 30110.762 6515.099 30073.912 6389.779 30038.042 6264.119 C 30001.812 6138.519 29966.082 6012.779 29930.482 5887.039 L 29877.812 5698.089 L 29851.442 5603.649 L 29825.632 5508.999 L 29865.882 5598.439 L 29905.642 5688.099 L 29985.162 5867.399 C 30037.692 5987.099 30090.152 6106.799 30142.062 6226.709 C 30194.312 6346.549 30245.592 6466.669 30297.282 6586.639 L 30451.052 6947.129 L 30738.892 7748.739 L 30979.952 8419.959 L 31195.072 9019.019"/>
</g>
</g>
</g>
<path d="M 38.475 12.15 L 41.667 3.315 L 44.898 3.315 L 39.995 15.063 L 36.966 15.063 L 32.081 3.314 L 35.302 3.314 L 38.474 12.15 L 38.475 12.15 Z M 48.738 10.923 L 48.738 15.063 L 45.837 15.063 L 45.837 3.314 L 51.332 3.314 C 52.389 3.314 53.317 3.476 54.118 3.799 C 54.923 4.121 55.542 4.581 55.974 5.179 C 56.406 5.77 56.622 6.446 56.622 7.203 C 56.622 8.355 56.148 9.264 55.201 9.931 C 54.26 10.592 52.953 10.923 51.282 10.923 L 48.738 10.923 Z M 48.738 8.963 L 51.332 8.963 C 52.099 8.963 52.683 8.812 53.082 8.511 C 53.488 8.21 53.692 7.78 53.692 7.22 C 53.692 6.644 53.488 6.179 53.082 5.824 C 52.677 5.469 52.115 5.286 51.399 5.275 L 48.738 5.275 L 48.738 8.963 Z M 69.682 15.063 L 66.779 15.063 L 61.13 7.333 L 61.13 15.063 L 58.23 15.063 L 58.23 3.314 L 61.13 3.314 L 66.789 11.06 L 66.789 3.315 L 69.682 3.315 L 69.682 15.063 Z" fill="#000" style=""/>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

+1
View File
@@ -0,0 +1 @@
*.a filter=lfs diff=lfs merge=lfs -text
+33
View File
@@ -0,0 +1,33 @@
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
**/build/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>
+2
View File
@@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
+2
View File
@@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
+35
View File
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>PacketTunnel</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSCameraUsageDescription</key>
<string>用于客服消息上传图片</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.networkextension.packet-tunnel</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
</dict>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>用于客服消息上传图片</string>
</dict>
</plist>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.vpntunnel.vpnzeus</string>
</array>
</dict>
</plist>
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
# Uncomment this line to define a global platform for your project
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
platform :ios, '14.0'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
# 添加打印语句
puts "Flutter Root Path: #{flutter_root}"
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
puts "flutter_install_all_ios_pods : #{File.dirname(File.realpath(__FILE__))}"
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
+950
View File
@@ -0,0 +1,950 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1273FB492B1EBCA4005B78AF /* leaf.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1273FB472B1EBC5E005B78AF /* leaf.xcframework */; };
1273FB4A2B1EBCA4005B78AF /* leaf.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1273FB472B1EBC5E005B78AF /* leaf.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2FD21F1125A363E300F556E0 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FD21F1025A363E300F556E0 /* PacketTunnelProvider.swift */; };
2FD21F1625A363E300F556E0 /* PacketTunnel.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 2FD21F0D25A363E300F556E0 /* PacketTunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
2FD21F2425A364B700F556E0 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FD21EF825A363AA00F556E0 /* NetworkExtension.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3E06F985293FACBB00E04D92 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FD21F1025A363E300F556E0 /* PacketTunnelProvider.swift */; };
3E06F989293FAFC600E04D92 /* LeafAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E06F988293FAFC600E04D92 /* LeafAdapter.swift */; };
3E06F98A293FAFC600E04D92 /* LeafAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E06F988293FAFC600E04D92 /* LeafAdapter.swift */; };
3E06F98C293FB8F600E04D92 /* TunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E06F98B293FB8F600E04D92 /* TunnelConfiguration.swift */; };
3E06F98D293FB8F600E04D92 /* TunnelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E06F98B293FB8F600E04D92 /* TunnelConfiguration.swift */; };
3EA6B274293F185700B2BABC /* FileManager+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA6B273293F185700B2BABC /* FileManager+Helpers.swift */; };
3EA6B276293F1AC500B2BABC /* template.conf in Resources */ = {isa = PBXBuildFile; fileRef = 3EA6B275293F1AC500B2BABC /* template.conf */; };
3EA6B278293F1D1600B2BABC /* URL+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA6B277293F1D1600B2BABC /* URL+Helpers.swift */; };
3EA6B27A293F1FAD00B2BABC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA6B279293F1FAD00B2BABC /* Logger.swift */; };
3EA6B27C293F68B500B2BABC /* VPNManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F50954A25A36FD0001A32D5 /* VPNManager.swift */; };
3EA6B27E293F69A400B2BABC /* VPNManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F50954A25A36FD0001A32D5 /* VPNManager.swift */; };
3EA6B27F293F6AB500B2BABC /* FileManager+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA6B273293F185700B2BABC /* FileManager+Helpers.swift */; };
3EA6B280293F6AB900B2BABC /* URL+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA6B277293F1D1600B2BABC /* URL+Helpers.swift */; };
3EA6B281293F6AF800B2BABC /* template.conf in Resources */ = {isa = PBXBuildFile; fileRef = 3EA6B275293F1AC500B2BABC /* template.conf */; };
3EA6B282293F6BA500B2BABC /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA6B279293F1FAD00B2BABC /* Logger.swift */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
7A31DD8228420C0B00E82EE1 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FD21EF825A363AA00F556E0 /* NetworkExtension.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
C09CB0942C50BC8D0028C461 /* leaf.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1273FB472B1EBC5E005B78AF /* leaf.xcframework */; };
DBC6F25A26C78B1D91884CE1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A9C0075B77637136AF52D8B /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
2FD21F1425A363E300F556E0 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 2FD21F0C25A363E300F556E0;
remoteInfo = PacketTunnel;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
1273FB4B2B1EBCA4005B78AF /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
1273FB4A2B1EBCA4005B78AF /* leaf.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
2FD21F0625A363AA00F556E0 /* Embed App Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
2FD21F1625A363E300F556E0 /* PacketTunnel.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1273FB472B1EBC5E005B78AF /* leaf.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = leaf.xcframework; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2F50954A25A36FD0001A32D5 /* VPNManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNManager.swift; sourceTree = "<group>"; };
2FD21EF825A363AA00F556E0 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
2FD21F0D25A363E300F556E0 /* PacketTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PacketTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; };
2FD21F1025A363E300F556E0 /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = "<group>"; };
2FD21F1225A363E300F556E0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
2FD21F1325A363E300F556E0 /* PacketTunnel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PacketTunnel.entitlements; sourceTree = "<group>"; };
2FD21F2325A364B600F556E0 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3E06F988293FAFC600E04D92 /* LeafAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeafAdapter.swift; sourceTree = "<group>"; };
3E06F98B293FB8F600E04D92 /* TunnelConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelConfiguration.swift; sourceTree = "<group>"; };
3EA6B273293F185700B2BABC /* FileManager+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Helpers.swift"; sourceTree = "<group>"; };
3EA6B275293F1AC500B2BABC /* template.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = template.conf; sourceTree = "<group>"; };
3EA6B277293F1D1600B2BABC /* URL+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Helpers.swift"; sourceTree = "<group>"; };
3EA6B279293F1FAD00B2BABC /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
4A9C0075B77637136AF52D8B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7F9A79C99E6BB92BFA8F918D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
8B949A6E3580C410A6129430 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9788364E2A66C2C5DE332140 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
2FD21F0A25A363E300F556E0 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7A31DD8228420C0B00E82EE1 /* NetworkExtension.framework in Frameworks */,
1273FB492B1EBCA4005B78AF /* leaf.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2FD21F2425A364B700F556E0 /* NetworkExtension.framework in Frameworks */,
DBC6F25A26C78B1D91884CE1 /* Pods_Runner.framework in Frameworks */,
C09CB0942C50BC8D0028C461 /* leaf.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2FD21F0F25A363E300F556E0 /* PacketTunnel */ = {
isa = PBXGroup;
children = (
2FD21F1225A363E300F556E0 /* Info.plist */,
2FD21F1325A363E300F556E0 /* PacketTunnel.entitlements */,
);
path = PacketTunnel;
sourceTree = "<group>";
};
3EA6B272293F183000B2BABC /* Helpers */ = {
isa = PBXGroup;
children = (
3EA6B273293F185700B2BABC /* FileManager+Helpers.swift */,
3EA6B277293F1D1600B2BABC /* URL+Helpers.swift */,
);
path = Helpers;
sourceTree = "<group>";
};
3EA6B27D293F699400B2BABC /* Shared */ = {
isa = PBXGroup;
children = (
3E06F988293FAFC600E04D92 /* LeafAdapter.swift */,
2FD21F1025A363E300F556E0 /* PacketTunnelProvider.swift */,
3EA6B272293F183000B2BABC /* Helpers */,
2F50954A25A36FD0001A32D5 /* VPNManager.swift */,
3EA6B279293F1FAD00B2BABC /* Logger.swift */,
3EA6B275293F1AC500B2BABC /* template.conf */,
3E06F98B293FB8F600E04D92 /* TunnelConfiguration.swift */,
);
path = Shared;
sourceTree = "<group>";
};
460845DE28877D00F1FA7B32 /* Pods */ = {
isa = PBXGroup;
children = (
7F9A79C99E6BB92BFA8F918D /* Pods-Runner.debug.xcconfig */,
8B949A6E3580C410A6129430 /* Pods-Runner.release.xcconfig */,
9788364E2A66C2C5DE332140 /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
3EA6B27D293F699400B2BABC /* Shared */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
2FD21F0F25A363E300F556E0 /* PacketTunnel */,
97C146EF1CF9000F007C117D /* Products */,
460845DE28877D00F1FA7B32 /* Pods */,
F6BCB37E43B89DAB5A76B9D0 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
2FD21F0D25A363E300F556E0 /* PacketTunnel.appex */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
2FD21F2325A364B600F556E0 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
F6BCB37E43B89DAB5A76B9D0 /* Frameworks */ = {
isa = PBXGroup;
children = (
1273FB472B1EBC5E005B78AF /* leaf.xcframework */,
2FD21EF825A363AA00F556E0 /* NetworkExtension.framework */,
4A9C0075B77637136AF52D8B /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
2FD21F0C25A363E300F556E0 /* PacketTunnel */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2FD21F1725A363E300F556E0 /* Build configuration list for PBXNativeTarget "PacketTunnel" */;
buildPhases = (
2FD21F0925A363E300F556E0 /* Sources */,
2FD21F0A25A363E300F556E0 /* Frameworks */,
2FD21F0B25A363E300F556E0 /* Resources */,
1273FB4B2B1EBCA4005B78AF /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = PacketTunnel;
productName = PacketTunnel;
productReference = 2FD21F0D25A363E300F556E0 /* PacketTunnel.appex */;
productType = "com.apple.product-type.app-extension";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
4A4528B4E4B302F57B5EDB65 /* [CP] Check Pods Manifest.lock */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
2FD21F0625A363AA00F556E0 /* Embed App Extensions */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
30B17F94E53B12A0859D0A8C /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
2FD21F1525A363E300F556E0 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1230;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
2FD21F0C25A363E300F556E0 = {
CreatedOnToolsVersion = 12.3;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
C09CB0932C50B5DF0028C461 /* XCRemoteSwiftPackageReference "SwiftLoader" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
2FD21F0C25A363E300F556E0 /* PacketTunnel */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
2FD21F0B25A363E300F556E0 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3EA6B276293F1AC500B2BABC /* template.conf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3EA6B281293F6AF800B2BABC /* template.conf in Resources */,
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
30B17F94E53B12A0859D0A8C /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
};
4A4528B4E4B302F57B5EDB65 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\necho \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\"\necho build\necho \">>>>>>>>>\"\n/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
2FD21F0925A363E300F556E0 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2FD21F1125A363E300F556E0 /* PacketTunnelProvider.swift in Sources */,
3EA6B278293F1D1600B2BABC /* URL+Helpers.swift in Sources */,
3EA6B27E293F69A400B2BABC /* VPNManager.swift in Sources */,
3E06F98A293FAFC600E04D92 /* LeafAdapter.swift in Sources */,
3EA6B274293F185700B2BABC /* FileManager+Helpers.swift in Sources */,
3E06F98D293FB8F600E04D92 /* TunnelConfiguration.swift in Sources */,
3EA6B27A293F1FAD00B2BABC /* Logger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
3EA6B282293F6BA500B2BABC /* Logger.swift in Sources */,
3EA6B280293F6AB900B2BABC /* URL+Helpers.swift in Sources */,
3EA6B27F293F6AB500B2BABC /* FileManager+Helpers.swift in Sources */,
3EA6B27C293F68B500B2BABC /* VPNManager.swift in Sources */,
3E06F989293FAFC600E04D92 /* LeafAdapter.swift in Sources */,
3E06F985293FACBB00E04D92 /* PacketTunnelProvider.swift in Sources */,
3E06F98C293FB8F600E04D92 /* TunnelConfiguration.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
2FD21F1525A363E300F556E0 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 2FD21F0C25A363E300F556E0 /* PacketTunnel */;
targetProxy = 2FD21F1425A363E300F556E0 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_BITCODE = NO;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MODULEMAP_FILE = "${PROJECT_DIR}/LeafFFI/module.modulemap";
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_INCLUDE_PATHS = "${PROJECT_DIR}/LeafFFI";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U288ZP9B22;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = UUVPN;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MODULEMAP_FILE = "${PROJECT_DIR}/LeafFFI/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.vpntunnel.vpnzeus;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_INCLUDE_PATHS = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
2FD21F1825A363E300F556E0 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnel.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 200;
DEVELOPMENT_TEAM = 26XWXKSR3B;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = PacketTunnel/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
MARKETING_VERSION = 2.0.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.vpntunnel.vpnzeus.PacketTunnel;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_INCLUDE_PATHS = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
2FD21F1925A363E300F556E0 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnel.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 200;
DEVELOPMENT_TEAM = 26XWXKSR3B;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = PacketTunnel/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
MARKETING_VERSION = 2.0.0;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.vpntunnel.vpnzeus.PacketTunnel;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_INCLUDE_PATHS = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
2FD21F1A25A363E300F556E0 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnel.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 200;
DEVELOPMENT_TEAM = 26XWXKSR3B;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = PacketTunnel/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
MARKETING_VERSION = 2.0.0;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.vpntunnel.vpnzeus.PacketTunnel;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_INCLUDE_PATHS = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_BITCODE = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MODULEMAP_FILE = "${PROJECT_DIR}/LeafFFI/module.modulemap";
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_INCLUDE_PATHS = "${PROJECT_DIR}/LeafFFI";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_BITCODE = NO;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MODULEMAP_FILE = "${PROJECT_DIR}/LeafFFI/module.modulemap";
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_INCLUDE_PATHS = "${PROJECT_DIR}/LeafFFI";
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U288ZP9B22;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = UUVPN;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MODULEMAP_FILE = "${PROJECT_DIR}/LeafFFI/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.vpntunnel.vpnzeus;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_INCLUDE_PATHS = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U288ZP9B22;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = UUVPN;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MODULEMAP_FILE = "${PROJECT_DIR}/LeafFFI/module.modulemap";
PRODUCT_BUNDLE_IDENTIFIER = com.vpntunnel.vpnzeus;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_INCLUDE_PATHS = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
2FD21F1725A363E300F556E0 /* Build configuration list for PBXNativeTarget "PacketTunnel" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2FD21F1825A363E300F556E0 /* Debug */,
2FD21F1925A363E300F556E0 /* Release */,
2FD21F1A25A363E300F556E0 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
C09CB0932C50B5DF0028C461 /* XCRemoteSwiftPackageReference "SwiftLoader" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/leoru/SwiftLoader";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "swiftloader",
"kind" : "remoteSourceControl",
"location" : "https://github.com/leoru/SwiftLoader",
"state" : {
"revision" : "3d03ac07764075bfab4c9ce9d5ba4556d6af350e",
"version" : "1.1.0"
}
}
],
"version" : 2
}
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "swiftloader",
"kind" : "remoteSourceControl",
"location" : "https://github.com/leoru/SwiftLoader",
"state" : {
"revision" : "3d03ac07764075bfab4c9ce9d5ba4556d6af350e",
"version" : "1.1.0"
}
}
],
"version" : 2
}

Some files were not shown because too many files have changed in this diff Show More