Compare commits

...

57 Commits

Author SHA1 Message Date
2dust
7e99b1ac78 up 1.9.32 2025-01-13 15:04:01 +08:00
2dust
6ff3a73bf2 Adjust UI for subscription 2025-01-13 14:56:48 +08:00
2dust
2a43b52344 Logcat add pull-down refresh 2025-01-13 14:31:36 +08:00
2dust
abff80ec23 Adjust UI 2025-01-13 12:51:26 +08:00
2dust
a4edf86195 Improved logcat 2025-01-13 12:50:35 +08:00
alphax-hue3682
0d0da6bfec Update Persian translate (#4256)
* Update Persian translate

* Update strings.xml
2025-01-12 13:47:18 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
e0c8ece9b5 Reproducible Builds for libhysteria2.so (#4249)
* Patch Go use 600296

* -buildvcs=false for libhysteria2

* fix if

* fixup! Build and cache libhysteria2.so (#4226)
2025-01-11 10:38:47 +08:00
2dust
4d875bc3d4 Add theme to SwitchCompat for tasker 2025-01-09 09:48:37 +08:00
2dust
3a6e23bcef Fix the bug of mux parameter taking 2025-01-08 11:23:21 +08:00
2dust
efd0716707 Custom configuration can use any outbound
https://github.com/2dust/v2rayNG/issues/4243
2025-01-07 17:14:23 +08:00
2dust
c94a5fb743 Update Luri Bakhtiari translation 2025-01-07 14:47:18 +08:00
2dust
047011f60b up 1.9.31 2025-01-07 14:21:08 +08:00
2dust
a54ed3a51a Update libs.versions.toml 2025-01-07 14:19:31 +08:00
2dust
c37f09bfcd Fix logcat 2025-01-07 14:03:26 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
1c7042463d Fixup! 7dbda3c (#4237) 2025-01-05 19:04:50 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
dcb003f9ab Submodules (#4234)
* add submodule AndroidLibXrayLite

* rm -r AndroidLibV2rayLite

* add submodule AndroidLibV2rayLite

* update cache key for libtun2socks due to submodules

* fetch-depth: '0'

* fail safe

* Revert "add submodule AndroidLibV2rayLite"

This reverts commit 816f75e0f9.

* sync with 2dust/AndroidLibXrayLite#90

* checkout to 664c389 of AndroidLibXrayLite

* refine cache key of libtun2socks
2025-01-05 11:52:31 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
7dbda3cee7 Build and cache libhysteria2.so (#4226)
* add submodule apernet/hysteria

* remove libhysteria2 binary from git repo

* libhysteria2.sh

* ignore *.so
2025-01-04 10:49:04 +08:00
solokot
26bee229a1 Update Russian translation (#4221) 2025-01-03 09:47:35 +08:00
alphax-hue3682
5bf2beb179 Update Persian translate (#4219)
* Update Persian translate

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml
2025-01-03 09:47:21 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
4a5c551678 ndk for gradlew (#4220) 2025-01-02 14:57:44 +08:00
2dust
277894215d up 1.9.30 2025-01-02 10:11:57 +08:00
alphax-hue3682
684e08a3a1 Update Persian translate (#4214)
* Update Persian translate

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml
2025-01-02 09:37:24 +08:00
2dust
19dbc2f9b9 up 1.9.29 2025-01-01 16:45:08 +08:00
2dust
833a1e06f0 Add VPN bypass LAN option
https://github.com/2dust/v2rayNG/pull/4208
2025-01-01 16:43:48 +08:00
2dust
daca0831a4 Remove the last rule from the Whitelist 2024-12-31 21:19:15 +08:00
2dust
337889c5f1 up 1.9.28 2024-12-29 14:29:22 +08:00
2dust
244d2d3866 Fix bugs related to routing rules
https://github.com/2dust/v2rayNG/issues/4196
https://github.com/2dust/v2rayNG/issues/4199
2024-12-29 11:06:08 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
c0fed0ba4f Download libv2ray from 2dust/AndroidLibXrayLite (#4200) 2024-12-28 19:46:51 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
affb107b9d Sagernet (#4194)
* switch to sagernet/gomobile

* arguments for rb

* match ndk version

* with more options

* nttld/setup-ndk#518
2024-12-28 19:29:00 +08:00
2dust
f96073af99 Update build.yml 2024-12-25 10:23:30 +08:00
2dust
496a0483d2 up 1.9.27 2024-12-24 17:32:06 +08:00
2dust
e11dca00bb Add release function to build 2024-12-24 17:31:32 +08:00
2dust
fde39bf34e Bug fix for isXray() 2024-12-24 15:03:10 +08:00
kore kas nadar
4f11bae238 Update Luri Bakhtiari translation (#4178) 2024-12-23 17:15:06 +08:00
2dust
f6282ba71f Ignore libhysteria2.so 2024-12-23 09:59:57 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
3edf1f4e1b Refine cache key (#4172) 2024-12-22 13:36:18 +08:00
886963226
41bc064083 Optimization logcat after change quickie-foss (#4171)
After changed quickie-foss, scanning cause lot of log. throttle log com.google.zxing.NotFoundException.
2024-12-22 10:21:55 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
eb8562e6b0 Ignore libtun2socks.so (#4169) 2024-12-22 10:04:23 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
68fbdd92c3 s/versionNameSuffix/applicationIdSuffix (#4168) 2024-12-21 21:08:21 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
02038a5d93 Build and cache libtun2socks and libv2ray (#4167)
* build libtun2socks

* Clean up binaries

* test cache

altrepo for testing

* switch to original repo
2024-12-21 20:35:17 +08:00
2dust
4fb8c2f4b2 org.gradle.jvmargs=-Xmx4096m 2024-12-21 17:54:03 +08:00
2dust
7afffa60c3 Code clean 2024-12-21 17:18:35 +08:00
2dust
0e6c860360 JavaVersion.VERSION_17 2024-12-21 16:43:26 +08:00
2dust
ebfbbfa08b Revert "Update build.yml (#4166)"
This reverts commit b5f182dfec.
2024-12-21 16:08:00 +08:00
886963226
b5f182dfec Update build.yml (#4166) 2024-12-21 14:47:28 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
4cf28d0ad0 Fix split apk (#4165) 2024-12-21 14:21:58 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
149bb049a5 Fix flavor build (#4164)
* Fix license report

* Upload both flavors
2024-12-21 14:09:52 +08:00
2dust
124702f0a2 Fix libs 2024-12-21 11:48:48 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
c1cebe578b fdroid flavor and split abi (#4162) 2024-12-21 11:18:41 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
e46c1ee849 switch to quickie-foss for QR code (#4161)
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
2024-12-21 11:18:16 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
70f1743114 Switch to gradle-license-plugin (#4160)
* switch to gradle-license-plugin

* generate licenseReleaseReport
2024-12-21 10:40:20 +08:00
2dust
54d520727e Add signature for build 2024-12-20 15:26:55 +08:00
alphax-hue3682
1f1e4db486 Update persian translate (#4158) 2024-12-20 15:08:29 +08:00
solokot
e536236634 Update Russian translation (#4156) 2024-12-20 11:16:55 +08:00
2dust
140c236da5 Add DNS hosts (Format: domain:address,…)
https://github.com/2dust/v2rayNG/issues/4147
2024-12-19 20:57:24 +08:00
2dust
69ede34274 up 1.9.26 2024-12-19 17:34:55 +08:00
ᡠᠵᡠᡳ ᡠᠵᡠ ᠮᠠᠨᡩ᠋ᠠᠨ
fcf6e22132 Add fastlane metadata for F-Droid (#4121)
* Add fastlane metadata

* fixup! Add fastlane metadata

* hoedown full_description.txt

* Remove title heading 1
2024-12-19 13:03:12 +08:00
75 changed files with 2109 additions and 342 deletions

View File

@@ -1,13 +1,14 @@
name: Build APK
on:
push:
workflow_dispatch:
inputs:
XRAY_CORE_VERSION:
description: 'Xray core version or commit hash'
release_tag:
required: false
type: string
push:
branches:
- master
jobs:
build:
@@ -16,6 +17,110 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: 'recursive'
fetch-depth: '0'
- name: Restore cached libtun2socks
id: cache-libtun2socks-restore
uses: actions/cache/restore@v4
with:
path: ${{ github.workspace }}/AndroidLibXrayLite/libs
key: libtun2socks-${{ runner.os }}-${{ hashFiles('.git/modules/AndroidLibXrayLite/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/AndroidLibXrayLite/modules/libancillary/HEAD') }}
- name: Setup Android NDK
uses: nttld/setup-ndk@v1
id: setup-ndk
# Same version as https://gitlab.com/fdroid/fdroiddata/metadata/com.v2ray.ang.yml
with:
ndk-version: r27
add-to-path: true
link-to-sdk: true
local-cache: true
- name: Restore Android Symlinks
run: |
directory="${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin"
find "$directory" -type l | while read link; do
current_target=$(readlink "$link")
new_target="$directory/$(basename "$current_target")"
ln -sf "$new_target" "$link"
echo "Changed $(basename "$link") from $current_target to $new_target"
done
- name: Build libtun2socks
if: steps.cache-libtun2socks-restore.outputs.cache-hit != 'true'
run: |
cd ${{ github.workspace }}/AndroidLibXrayLite
bash compile-tun2socks.sh
tar -xvzf libtun2socks.so.tgz
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- name: Save libtun2socks
if: steps.cache-libtun2socks-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ${{ github.workspace }}/AndroidLibXrayLite/libs
key: libtun2socks-${{ runner.os }}-${{ hashFiles('.git/modules/AndroidLibXrayLite/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/AndroidLibXrayLite/modules/libancillary/HEAD') }}
- name: Copy libtun2socks
run: |
cp -r ${{ github.workspace }}/AndroidLibXrayLite/libs ${{ github.workspace }}/V2rayNG/app
- name: Fetch AndroidLibXrayLite tag
run: |
pushd AndroidLibXrayLite
CURRENT_TAG=$(git describe --tags --abbrev=0)
echo "Current tag in this repo: $CURRENT_TAG"
echo "CURRENT_TAG=$CURRENT_TAG" >> $GITHUB_ENV
popd
- name: Download libv2ray
uses: robinraju/release-downloader@v1
with:
repository: '2dust/AndroidLibXrayLite'
tag: ${{ env.CURRENT_TAG }}
fileName: 'libv2ray.aar'
out-file-path: V2rayNG/app/libs/
- name: Restore cached libhysteria2
id: cache-libhysteria2-restore
uses: actions/cache/restore@v4
with:
path: ${{ github.workspace }}/hysteria/libs
key: libhysteria2-${{ runner.os }}-${{ hashFiles('.git/modules/hysteria/HEAD') }}-${{ hashFiles('libhysteria2.sh') }}
- name: Setup Golang
if: steps.cache-libhysteria2-restore.outputs.cache-hit != 'true'
uses: actions/setup-go@v5
with:
go-version-file: 'AndroidLibXrayLite/go.mod'
- name: Patch Go use 600296
if: steps.cache-libhysteria2-restore.outputs.cache-hit != 'true'
#https://go-review.googlesource.com/c/go/+/600296
run: |
cd "$(go env GOROOT)"
curl "https://go-review.googlesource.com/changes/go~600296/revisions/5/patch" | base64 -d | patch --verbose -p 1
- name: Build libhysteria2
if: steps.cache-libhysteria2-restore.outputs.cache-hit != 'true'
run: |
bash libhysteria2.sh
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- name: Save libhysteria2
if: steps.cache-libhysteria2-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ${{ github.workspace }}/hysteria/libs
key: libhysteria2-${{ runner.os }}-${{ hashFiles('.git/modules/hysteria/HEAD') }}-${{ hashFiles('libhysteria2.sh') }}
- name: Copy libhysteria2
run: |
cp -r ${{ github.workspace }}/hysteria/libs ${{ github.workspace }}/V2rayNG/app
- name: Setup Java
uses: actions/setup-java@v4
@@ -23,71 +128,51 @@ jobs:
distribution: 'temurin'
java-version: '21'
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version: '1.23.2'
cache: false
- name: Patch Go use 600296
#https://go-review.googlesource.com/c/go/+/600296
run: |
cd "$(go env GOROOT)"
curl "https://go-review.googlesource.com/changes/go~600296/revisions/5/patch" | base64 -d | patch --verbose -p 1
- name: Install gomobile
run: |
go install golang.org/x/mobile/cmd/gomobile@v0.0.0-20240806205939-81131f6468ab
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Setup Android environment
uses: android-actions/setup-android@v3
- name: Build dependencies
run: |
mkdir ${{ github.workspace }}/build
cd ${{ github.workspace }}/build
git clone --depth=1 -b main https://github.com/2dust/AndroidLibXrayLite.git
cd AndroidLibXrayLite
go get github.com/xtls/xray-core@${{ github.event.inputs.XRAY_CORE_VERSION }} || true
gomobile init
go mod tidy -v
gomobile bind -v -androidapi 21 -ldflags='-s -w' ./
cp *.aar ${{ github.workspace }}/V2rayNG/app/libs/
- name: Decode Keystore
uses: timheuer/base64-to-file@v1
id: android_keystore
with:
fileName: "android_keystore.jks"
encodedString: ${{ secrets.APP_KEYSTORE_BASE64 }}
- name: Build APK
run: |
cd ${{ github.workspace }}/V2rayNG
chmod 755 gradlew
./gradlew assembleDebug
./gradlew licenseFdroidReleaseReport
./gradlew assembleRelease -Pandroid.injected.signing.store.file=${{ steps.android_keystore.outputs.filePath }} -Pandroid.injected.signing.store.password=${{ secrets.APP_KEYSTORE_PASSWORD }} -Pandroid.injected.signing.key.alias=${{ secrets.APP_KEYSTORE_ALIAS }} -Pandroid.injected.signing.key.password=${{ secrets.APP_KEY_PASSWORD }}
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- name: Upload arm64-v8a APK
uses: actions/upload-artifact@v4
if: ${{ success() }}
with:
name: arm64-v8a
path: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/debug/*arm64-v8a*.apk
path: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/*/release/*arm64-v8a*.apk
- name: Upload armeabi-v7a APK
uses: actions/upload-artifact@v4
if: ${{ success() }}
with:
name: armeabi-v7a
path: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/debug/*armeabi-v7a*.apk
path: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/*/release/*armeabi-v7a*.apk
- name: Upload x86 APK
uses: actions/upload-artifact@v4
if: ${{ success() }}
with:
name: x86-apk
path: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/debug/*x86*.apk
- name: Upload Other APKs
uses: actions/upload-artifact@v4
path: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/*/release/*x86*.apk
- name: Upload to release
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
name: others-apk
path: |
${{ github.workspace }}/V2rayNG/app/build/outputs/apk/debug
!${{ github.workspace }}/V2rayNG/app/build/outputs/apk/debug/*arm64-v8a*.apk
!${{ github.workspace }}/V2rayNG/app/build/outputs/apk/debug/*armeabi-v7a*.apk
!${{ github.workspace }}/V2rayNG/app/build/outputs/apk/debug/*x86*.apk
file: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/*playstore*/release/*.apk
tag: ${{ github.event.inputs.release_tag }}
file_glob: true
prerelease: true

16
.github/workflows/fastlane.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Validate Fastlane metadata
on:
workflow_dispatch:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
go:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate Fastlane Supply Metadata
uses: ashutoshgngwr/validate-fastlane-supply-metadata@v2.0.0

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
V2rayNG/app/release/output.json
.idea/
.gradle/
*.so

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "hysteria"]
path = hysteria
url = https://github.com/apernet/hysteria
[submodule "AndroidLibXrayLite"]
path = AndroidLibXrayLite
url = https://github.com/2dust/AndroidLibXrayLite

1
AndroidLibXrayLite Submodule

Submodule AndroidLibXrayLite added at 664c3892e2

View File

@@ -1,7 +1,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("com.google.android.gms.oss-licenses-plugin")
id("com.jaredsburrows.license")
}
android {
@@ -12,20 +12,26 @@ android {
applicationId = "com.v2ray.ang"
minSdk = 21
targetSdk = 35
versionCode = 621
versionName = "1.9.25"
versionCode = 628
versionName = "1.9.32"
multiDexEnabled = true
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
splits {
abi {
isEnable = true
include(
"arm64-v8a",
"armeabi-v7a",
"x86_64",
"x86"
)
isUniversalApk = true
reset()
if (abiFilterList != null && abiFilterList.isNotEmpty()) {
include(*abiFilterList.toTypedArray())
} else {
include(
"arm64-v8a",
"armeabi-v7a",
"x86_64",
"x86"
)
}
isUniversalApk = abiFilterList.isNullOrEmpty()
}
}
@@ -42,6 +48,19 @@ android {
}
}
flavorDimensions.add("distribution")
productFlavors {
create("fdroid") {
dimension = "distribution"
applicationIdSuffix = ".fdroid"
buildConfigField("String", "DISTRIBUTION", "\"F-Droid\"")
}
create("playstore") {
dimension = "distribution"
buildConfigField("String", "DISTRIBUTION", "\"Play Store\"")
}
}
sourceSets {
getByName("main") {
jniLibs.srcDirs("libs")
@@ -50,34 +69,55 @@ android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
jvmTarget = JavaVersion.VERSION_17.toString()
}
applicationVariants.all {
val variant = this
val versionCodes =
mapOf("armeabi-v7a" to 4, "arm64-v8a" to 4, "x86" to 4, "x86_64" to 4, "universal" to 4)
val isFdroid = variant.productFlavors.any { it.name == "fdroid" }
if (isFdroid) {
val versionCodes =
mapOf("armeabi-v7a" to 2, "arm64-v8a" to 1, "x86" to 4, "x86_64" to 3, "universal" to 0
)
variant.outputs
.map { it as com.android.build.gradle.internal.api.ApkVariantOutputImpl }
.forEach { output ->
val abi = if (output.getFilter("ABI") != null)
output.getFilter("ABI")
else
"universal"
output.outputFileName = "v2rayNG_${variant.versionName}_${abi}.apk"
if (versionCodes.containsKey(abi)) {
output.versionCodeOverride =
(1000000 * versionCodes[abi]!!).plus(variant.versionCode)
} else {
return@forEach
variant.outputs
.map { it as com.android.build.gradle.internal.api.ApkVariantOutputImpl }
.forEach { output ->
val abi = output.getFilter("ABI") ?: "universal"
output.outputFileName = "v2rayNG_${variant.versionName}-fdroid_${abi}.apk"
if (versionCodes.containsKey(abi)) {
output.versionCodeOverride =
(100 * variant.versionCode + versionCodes[abi]!!).plus(5000000)
} else {
return@forEach
}
}
}
} else {
val versionCodes =
mapOf("armeabi-v7a" to 4, "arm64-v8a" to 4, "x86" to 4, "x86_64" to 4, "universal" to 4)
variant.outputs
.map { it as com.android.build.gradle.internal.api.ApkVariantOutputImpl }
.forEach { output ->
val abi = if (output.getFilter("ABI") != null)
output.getFilter("ABI")
else
"universal"
output.outputFileName = "v2rayNG_${variant.versionName}_${abi}.apk"
if (versionCodes.containsKey(abi)) {
output.versionCodeOverride =
(1000000 * versionCodes[abi]!!).plus(variant.versionCode)
} else {
return@forEach
}
}
}
}
buildFeatures {
@@ -104,6 +144,7 @@ dependencies {
implementation(libs.androidx.constraintlayout)
implementation(libs.preference.ktx)
implementation(libs.recyclerview)
implementation(libs.androidx.swiperefreshlayout)
// UI Libraries
implementation(libs.material)
@@ -125,7 +166,7 @@ dependencies {
implementation(libs.language.json)
// Intent and Utility Libraries
implementation(libs.quickie.bundled)
implementation(libs.quickie.foss)
implementation(libs.core)
// AndroidX Lifecycle and Architecture Components
@@ -146,6 +187,5 @@ dependencies {
androidTestImplementation(libs.androidx.espresso.core)
testImplementation(libs.org.mockito.mockito.inline)
testImplementation(libs.mockito.kotlin)
// Oss Licenses
implementation(libs.play.services.oss.licenses)
coreLibraryDesugaring(libs.desugar.jdk.libs)
}

Binary file not shown.

Binary file not shown.

View File

@@ -99,10 +99,5 @@
"domain": [
"geosite:cn"
]
},
{
"remarks": "最终代理",
"port": "0-65535",
"outboundTag": "proxy"
}
]

View File

@@ -40,10 +40,5 @@
"ip": [
"geoip:ir"
]
},
{
"remarks": "Final Agent",
"port": "0-65535",
"outboundTag": "proxy"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,7 @@ object AppConfig {
const val PREF_APPEND_HTTP_PROXY = "pref_append_http_proxy"
const val PREF_LOCAL_DNS_PORT = "pref_local_dns_port"
const val PREF_VPN_DNS = "pref_vpn_dns"
const val PREF_VPN_BYPASS_LAN = "pref_vpn_bypass_lan"
const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy"
const val PREF_ROUTING_RULESET = "pref_routing_ruleset"
const val PREF_MUX_ENABLED = "pref_mux_enabled"
@@ -50,6 +51,7 @@ object AppConfig {
const val PREF_SOCKS_PORT = "pref_socks_port"
const val PREF_REMOTE_DNS = "pref_remote_dns"
const val PREF_DOMESTIC_DNS = "pref_domestic_dns"
const val PREF_DNS_HOSTS = "pref_dns_hosts"
const val PREF_DELAY_TEST_URL = "pref_delay_test_url"
const val PREF_LOGLEVEL = "pref_core_loglevel"
const val PREF_MODE = "pref_mode"

View File

@@ -1,5 +1,7 @@
package com.v2ray.ang.dto
import com.v2ray.ang.AppConfig.LOOPBACK
import com.v2ray.ang.AppConfig.PORT_SOCKS
import com.v2ray.ang.AppConfig.TAG_BLOCKED
import com.v2ray.ang.AppConfig.TAG_DIRECT
import com.v2ray.ang.AppConfig.TAG_PROXY
@@ -66,6 +68,9 @@ data class ProfileItem(
}
fun getServerAddressAndPort(): String {
if (server.isNullOrEmpty() && configType == EConfigType.CUSTOM) {
return "$LOOPBACK:$PORT_SOCKS"
}
return Utils.getIpv6Address(server) + ":" + serverPort
}

View File

@@ -476,9 +476,9 @@ data class V2rayConfig(
data class MuxBean(
var enabled: Boolean,
var concurrency: Int = 8,
var xudpConcurrency: Int = 8,
var xudpProxyUDP443: String = "",
var concurrency: Int? = null,
var xudpConcurrency: Int? = null,
var xudpProxyUDP443: String? = null,
)
fun getServerAddress(): String? {

View File

@@ -95,4 +95,4 @@ inline fun <reified T : Serializable> Intent.serializable(key: String): T? = whe
else -> @Suppress("DEPRECATION") getSerializableExtra(key) as? T
}
inline fun CharSequence?.isNotNullEmpty(): Boolean = (this != null && this.isNotEmpty())
fun CharSequence?.isNotNullEmpty(): Boolean = (this != null && this.isNotEmpty())

View File

@@ -349,10 +349,6 @@ object MmkvManager {
return settingsStorage.decodeBool(key, defaultValue)
}
fun decodeSettingsInt(key: String, defaultValue: Int): Int {
return settingsStorage.decodeInt(key, defaultValue)
}
fun decodeSettingsStringSet(key: String): MutableSet<String>? {
return settingsStorage.decodeStringSet(key)
}

View File

@@ -9,9 +9,11 @@ import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.AppConfig.GEOIP_PRIVATE
import com.v2ray.ang.AppConfig.GEOSITE_PRIVATE
import com.v2ray.ang.AppConfig.TAG_DIRECT
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.RoutingType
import com.v2ray.ang.dto.RulesetItem
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.handler.MmkvManager.decodeServerConfig
import com.v2ray.ang.handler.MmkvManager.decodeServerList
import com.v2ray.ang.util.JsonUtil
@@ -91,8 +93,10 @@ object SettingsManager {
fun saveRoutingRuleset(index: Int, ruleset: RulesetItem?) {
if (ruleset == null) return
val rulesetList = MmkvManager.decodeRoutingRulesets()
if (rulesetList.isNullOrEmpty()) return
var rulesetList = MmkvManager.decodeRoutingRulesets()
if (rulesetList.isNullOrEmpty()) {
rulesetList = mutableListOf()
}
if (index < 0 || index >= rulesetList.count()) {
rulesetList.add(0, ruleset)
@@ -113,6 +117,25 @@ object SettingsManager {
}
fun routingRulesetsBypassLan(): Boolean {
val vpnBypassLan = MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_BYPASS_LAN) ?: "0"
if (vpnBypassLan == "1") {
return true
} else if (vpnBypassLan == "2") {
return false
}
//Follow config
val guid = MmkvManager.getSelectServer() ?: return false
val config = MmkvManager.decodeServerConfig(guid) ?: return false
if (config.configType == EConfigType.CUSTOM) {
val raw = MmkvManager.decodeServerRaw(guid) ?: return false
val v2rayConfig = JsonUtil.fromJson(raw, V2rayConfig::class.java)
val exist = v2rayConfig.routing.rules.filter { it.outboundTag == TAG_DIRECT }?.any {
it.domain?.contains(GEOSITE_PRIVATE) == true || it.ip?.contains(GEOIP_PRIVATE) == true
}
return exist == true
}
val rulesetItems = MmkvManager.decodeRoutingRulesets()
val exist = rulesetItems?.filter { it.enabled && it.outboundTag == TAG_DIRECT }?.any {
it.domain?.contains(GEOSITE_PRIVATE) == true || it.ip?.contains(GEOIP_PRIVATE) == true

View File

@@ -39,6 +39,7 @@ import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.RulesetItem
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.dto.V2rayConfig.RoutingBean.RulesBean
import com.v2ray.ang.extension.isNotNullEmpty
import com.v2ray.ang.fmt.HttpFmt
import com.v2ray.ang.fmt.Hysteria2Fmt
import com.v2ray.ang.fmt.ShadowsocksFmt
@@ -239,7 +240,7 @@ object V2rayConfigManager {
val rulesetItems = MmkvManager.decodeRoutingRulesets()
rulesetItems?.forEach { key ->
if (key != null && key.enabled && key.outboundTag == tag && !key.domain.isNullOrEmpty()) {
if (key.enabled && key.outboundTag == tag && !key.domain.isNullOrEmpty()) {
key.domain?.forEach {
if (it != GEOSITE_PRIVATE
&& (it.startsWith("geosite:") || it.startsWith("domain:"))
@@ -333,7 +334,7 @@ object V2rayConfigManager {
remoteDns.forEach {
servers.add(it)
}
if (proxyDomain.size > 0) {
if (proxyDomain.isNotEmpty()) {
servers.add(
V2rayConfig.DnsBean.ServersBean(
address = remoteDns.first(),
@@ -347,7 +348,7 @@ object V2rayConfigManager {
val directDomain = userRule2Domain(TAG_DIRECT)
val isCnRoutingMode = directDomain.contains(GEOSITE_CN)
val geoipCn = arrayListOf(GEOIP_CN)
if (directDomain.size > 0) {
if (directDomain.isNotEmpty()) {
servers.add(
V2rayConfig.DnsBean.ServersBean(
address = domesticDns.first(),
@@ -369,9 +370,23 @@ object V2rayConfigManager {
)
}
//User DNS hosts
try {
val userHosts = MmkvManager.decodeSettingsString(AppConfig.PREF_DNS_HOSTS)
if (userHosts.isNotNullEmpty()) {
var userHostsMap = userHosts?.split(",")
?.filter { it.isNotEmpty() }
?.filter { it.contains(":") }
?.associate { it.split(":").let { (k, v) -> k to v } }
if (userHostsMap != null) hosts.putAll(userHostsMap)
}
} catch (e: Exception) {
e.printStackTrace()
}
//block dns
val blkDomain = userRule2Domain(TAG_BLOCKED)
if (blkDomain.size > 0) {
if (blkDomain.isNotEmpty()) {
hosts.putAll(blkDomain.map { it to LOOPBACK })
}
@@ -423,21 +438,18 @@ object V2rayConfigManager {
|| protocol.equals(EConfigType.HYSTERIA2.name, true)
) {
muxEnabled = false
} else if (protocol.equals(EConfigType.VLESS.name, true)
&& outbound.settings?.vnext?.first()?.users?.first()?.flow?.isNotEmpty() == true
) {
muxEnabled = false
} else if (outbound.streamSettings?.network == NetworkType.XHTTP.type) {
muxEnabled = false
}
if (muxEnabled == true) {
outbound.mux?.enabled = true
outbound.mux?.concurrency =
MmkvManager.decodeSettingsInt(AppConfig.PREF_MUX_CONCURRENCY, 8)
outbound.mux?.xudpConcurrency =
MmkvManager.decodeSettingsInt(AppConfig.PREF_MUX_XUDP_CONCURRENCY, 16)
outbound.mux?.xudpProxyUDP443 =
MmkvManager.decodeSettingsString(AppConfig.PREF_MUX_XUDP_QUIC) ?: "reject"
outbound.mux?.concurrency = MmkvManager.decodeSettingsString(AppConfig.PREF_MUX_CONCURRENCY, "8").orEmpty().toInt()
outbound.mux?.xudpConcurrency = MmkvManager.decodeSettingsString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "16").orEmpty().toInt()
outbound.mux?.xudpProxyUDP443 = MmkvManager.decodeSettingsString(AppConfig.PREF_MUX_XUDP_QUIC,"reject")
if (protocol.equals(EConfigType.VLESS.name, true) && outbound.settings?.vnext?.first()?.users?.first()?.flow?.isNotEmpty() == true) {
outbound.mux?.concurrency = -1
}
} else {
outbound.mux?.enabled = false
outbound.mux?.concurrency = -1

View File

@@ -222,7 +222,7 @@ object PluginManager {
return File(pluginDir, pluginId).absolutePath
}
fun ComponentInfo.loadString(key: String) = when (val value = metaData.get(key)) {
fun ComponentInfo.loadString(key: String) = when (val value = metaData.getString(key)) {
is String -> value
is Int -> AngApplication.application.packageManager.getResourcesForApplication(applicationInfo)
.getString(value)

View File

@@ -4,6 +4,7 @@ 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
@@ -19,6 +20,7 @@ import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.AppConfig.TAG_DIRECT
import com.v2ray.ang.AppConfig.VPN
import com.v2ray.ang.R
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.extension.toSpeedString
import com.v2ray.ang.extension.toast
@@ -67,7 +69,10 @@ object V2RayServiceManager {
if (v2rayPoint.isRunning) return
val guid = MmkvManager.getSelectServer() ?: return
val config = MmkvManager.decodeServerConfig(guid) ?: return
if (!Utils.isValidUrl(config.server) && !Utils.isIpAddress(config.server)) return
if (config.configType != EConfigType.CUSTOM
&& !Utils.isValidUrl(config.server)
&& !Utils.isIpAddress(config.server)
) return
// val result = V2rayConfigUtil.getV2rayConfig(context, guid)
// if (!result.status) return
@@ -353,7 +358,12 @@ object V2RayServiceManager {
fun cancelNotification() {
val service = serviceControl?.get()?.getService() ?: return
service.stopForeground(true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
service.stopForeground(Service.STOP_FOREGROUND_REMOVE)
} else {
service.stopForeground(true)
}
mBuilder = null
mDisposable?.dispose()
mDisposable = null

View File

@@ -20,7 +20,6 @@ import com.v2ray.ang.util.ZipUtil
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
class AboutActivity : BaseActivity() {
@@ -90,7 +89,12 @@ class AboutActivity : BaseActivity() {
Utils.openUri(this, AppConfig.v2rayNGIssues)
}
binding.layoutOssLicenses.setOnClickListener{
startActivity(Intent(this, OssLicensesMenuActivity::class.java))
val webView = android.webkit.WebView(this);
webView.loadUrl("file:///android_asset/open_source_licenses.html");
android.app.AlertDialog.Builder(this)
.setTitle("Open source licenses")
.setView(webView)
.setPositiveButton("OK", android.content.DialogInterface.OnClickListener { dialog, whichButton -> dialog.dismiss() }).show()
}
binding.layoutTgChannel.setOnClickListener {

View File

@@ -1,13 +1,13 @@
package com.v2ray.ang.ui
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.method.ScrollingMovementMethod
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.appcompat.widget.SearchView
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.v2ray.ang.AppConfig.ANG_PACKAGE
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityLogcatBinding
@@ -18,10 +18,13 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
class LogcatActivity : BaseActivity() {
private val binding by lazy {
ActivityLogcatBinding.inflate(layoutInflater)
}
class LogcatActivity : BaseActivity(), SwipeRefreshLayout.OnRefreshListener {
private val binding by lazy { ActivityLogcatBinding.inflate(layoutInflater) }
var logsetsAll: MutableList<String> = mutableListOf()
var logsets: MutableList<String> = mutableListOf()
private val adapter by lazy { LogcatRecyclerAdapter(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -29,63 +32,118 @@ class LogcatActivity : BaseActivity() {
title = getString(R.string.title_logcat)
logcat(false)
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
binding.recyclerView.adapter = adapter
binding.recyclerView.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
binding.refreshLayout.setOnRefreshListener(this)
logsets.add(getString(R.string.pull_down_to_refresh))
}
private fun logcat(shouldFlushLog: Boolean) {
binding.pbWaiting.visibility = View.VISIBLE
private fun getLogcat() {
lifecycleScope.launch(Dispatchers.Default) {
try {
if (shouldFlushLog) {
val lst = linkedSetOf("logcat", "-c")
withContext(Dispatchers.IO) {
val process = Runtime.getRuntime().exec(lst.toTypedArray())
process.waitFor()
}
}
val lst = linkedSetOf(
"logcat", "-d", "-v", "time", "-s",
"GoLog,tun2socks,$ANG_PACKAGE,AndroidRuntime,System.err"
)
try {
binding.refreshLayout.isRefreshing = true
lifecycleScope.launch(Dispatchers.Default) {
val lst = LinkedHashSet<String>()
lst.add("logcat")
lst.add("-d")
lst.add("-v")
lst.add("time")
lst.add("-s")
lst.add("GoLog,tun2socks,${ANG_PACKAGE},AndroidRuntime,System.err")
val process = withContext(Dispatchers.IO) {
Runtime.getRuntime().exec(lst.toTypedArray())
}
val allText = process.inputStream.bufferedReader().use { it.readText() }
withContext(Dispatchers.Main) {
binding.tvLogcat.text = allText
binding.tvLogcat.movementMethod = ScrollingMovementMethod()
binding.pbWaiting.visibility = View.GONE
Handler(Looper.getMainLooper()).post { binding.svLogcat.fullScroll(View.FOCUS_DOWN) }
val allText = process.inputStream.bufferedReader().use { it.readLines() }
launch(Dispatchers.Main) {
logsetsAll = allText.toMutableList()
logsets = allText.toMutableList()
adapter.notifyDataSetChanged()
binding.refreshLayout.isRefreshing = false
}
} catch (e: IOException) {
withContext(Dispatchers.Main) {
binding.pbWaiting.visibility = View.GONE
toast(R.string.toast_failure)
}
e.printStackTrace()
}
} catch (e: IOException) {
e.printStackTrace()
}
}
private fun clearLogcat() {
try {
lifecycleScope.launch(Dispatchers.Default) {
val lst = LinkedHashSet<String>()
lst.add("logcat")
lst.add("-c")
withContext(Dispatchers.IO) {
val process = Runtime.getRuntime().exec(lst.toTypedArray())
process.waitFor()
}
launch(Dispatchers.Main) {
logsetsAll.clear()
logsets.clear()
adapter.notifyDataSetChanged()
}
}
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_logcat, menu)
val searchItem = menu.findItem(R.id.search_view)
if (searchItem != null) {
val searchView = searchItem.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean = false
override fun onQueryTextChange(newText: String?): Boolean {
filterLogs(newText)
return false
}
})
searchView.setOnCloseListener {
filterLogs("")
false
}
}
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.copy_all -> {
Utils.setClipboard(this, binding.tvLogcat.text.toString())
Utils.setClipboard(this, logsets.joinToString("\n"))
toast(R.string.toast_success)
true
}
R.id.clear_all -> {
logcat(true)
clearLogcat()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun filterLogs(content: String?): Boolean {
val key = content?.trim()
logsets = if (key.isNullOrEmpty()) {
logsetsAll.toMutableList()
} else {
logsetsAll.filter { it.contains(key) }.toMutableList()
}
adapter?.notifyDataSetChanged()
return true
}
override fun onRefresh() {
getLogcat()
}
}

View File

@@ -0,0 +1,31 @@
package com.v2ray.ang.ui
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.v2ray.ang.databinding.ItemRecyclerLogcatBinding
class LogcatRecyclerAdapter(val activity: LogcatActivity) : RecyclerView.Adapter<LogcatRecyclerAdapter.MainViewHolder>() {
private var mActivity: LogcatActivity = activity
override fun getItemCount() = mActivity.logsets.size
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
val content = mActivity.logsets[position]
holder.itemSubSettingBinding.logContent.text = content
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
return MainViewHolder(
ItemRecyclerLogcatBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
class MainViewHolder(val itemSubSettingBinding: ItemRecyclerLogcatBinding) : RecyclerView.ViewHolder(itemSubSettingBinding.root)
}

View File

@@ -387,7 +387,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
}
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do noting
}
.show()
@@ -407,7 +407,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
}
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do noting
}
.show()
@@ -427,7 +427,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
}
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do noting
}
.show()

View File

@@ -143,7 +143,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
.setPositiveButton(android.R.string.ok) { _, _ ->
removeServer(guid, position)
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do noting
}
.show()

View File

@@ -95,7 +95,7 @@ class RoutingEditActivity : BaseActivity() {
}
}
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
// do nothing
}
.show()

View File

@@ -105,7 +105,7 @@ class RoutingSettingActivity : BaseActivity() {
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do noting
}
.show()
@@ -134,7 +134,7 @@ class RoutingSettingActivity : BaseActivity() {
}
}
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do nothing
}
.show()
@@ -189,7 +189,7 @@ class RoutingSettingActivity : BaseActivity() {
}
}
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do nothing
}
.show()

View File

@@ -600,7 +600,7 @@ class ServerActivity : BaseActivity() {
MmkvManager.removeServer(editGuid)
finish()
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
// do nothing
}
.show()

View File

@@ -106,7 +106,7 @@ class ServerCustomConfigActivity : BaseActivity() {
MmkvManager.removeServer(editGuid)
finish()
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
// do nothing
}
.show()

View File

@@ -43,6 +43,7 @@ class SettingsActivity : BaseActivity() {
private val appendHttpProxy by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_APPEND_HTTP_PROXY) }
private val localDnsPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_LOCAL_DNS_PORT) }
private val vpnDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_VPN_DNS) }
private val vpnBypassLan by lazy { findPreference<ListPreference>(AppConfig.PREF_VPN_BYPASS_LAN) }
private val mux by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_MUX_ENABLED) }
private val muxConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_CONCURRENCY) }
@@ -60,6 +61,7 @@ class SettingsActivity : BaseActivity() {
private val socksPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_SOCKS_PORT) }
private val remoteDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_REMOTE_DNS) }
private val domesticDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_DOMESTIC_DNS) }
private val dnsHosts by lazy { findPreference<EditTextPreference>(AppConfig.PREF_DNS_HOSTS) }
private val delayTestUrl by lazy { findPreference<EditTextPreference>(AppConfig.PREF_DELAY_TEST_URL) }
private val mode by lazy { findPreference<ListPreference>(AppConfig.PREF_MODE) }
@@ -152,6 +154,11 @@ class SettingsActivity : BaseActivity() {
domesticDns?.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
true
}
dnsHosts?.setOnPreferenceChangeListener { _, any ->
val nval = any as String
dnsHosts?.summary = nval
true
}
delayTestUrl?.setOnPreferenceChangeListener { _, any ->
val nval = any as String
delayTestUrl?.summary = if (nval == "") AppConfig.DelayTestUrl else nval
@@ -194,6 +201,7 @@ class SettingsActivity : BaseActivity() {
socksPort?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_SOCKS_PORT, AppConfig.PORT_SOCKS)
remoteDns?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_REMOTE_DNS, AppConfig.DNS_PROXY)
domesticDns?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_DOMESTIC_DNS, AppConfig.DNS_DIRECT)
dnsHosts?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_DNS_HOSTS)
delayTestUrl?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_DELAY_TEST_URL, AppConfig.DelayTestUrl)
initSharedPreference()
@@ -239,6 +247,7 @@ class SettingsActivity : BaseActivity() {
}
listOf(
AppConfig.PREF_VPN_BYPASS_LAN,
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
AppConfig.PREF_MUX_XUDP_QUIC,
AppConfig.PREF_FRAGMENT_PACKETS,
@@ -262,6 +271,8 @@ class SettingsActivity : BaseActivity() {
appendHttpProxy?.isEnabled = vpn
localDnsPort?.isEnabled = vpn
vpnDns?.isEnabled = vpn
vpnBypassLan?.isEnabled = vpn
vpn
if (vpn) {
updateLocalDns(
MmkvManager.decodeSettingsBool(

View File

@@ -113,7 +113,7 @@ class SubEditActivity : BaseActivity() {
}
}
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
// do nothing
}
.show()

View File

@@ -333,7 +333,7 @@ class UserAssetActivity : BaseActivity() {
MmkvManager.removeAssetUrl(item.first)
initAssets()
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do noting
}
.show()

View File

@@ -116,7 +116,7 @@ class UserAssetUrlActivity : BaseActivity() {
MmkvManager.removeAssetUrl(editAssetId)
finish()
}
.setNegativeButton(android.R.string.no) { _, _ ->
.setNegativeButton(android.R.string.cancel) { _, _ ->
// do nothing
}
.show()

View File

@@ -498,7 +498,7 @@ object Utils {
ContextCompat.RECEIVER_NOT_EXPORTED
}
fun isXray(): Boolean = (ANG_PACKAGE == "com.v2ray.ang")
fun isXray(): Boolean = (ANG_PACKAGE.startsWith("com.v2ray.ang"))
}

View File

@@ -29,8 +29,10 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
when (key) {
AppConfig.PREF_MODE,
AppConfig.PREF_VPN_DNS,
AppConfig.PREF_VPN_BYPASS_LAN,
AppConfig.PREF_REMOTE_DNS,
AppConfig.PREF_DOMESTIC_DNS,
AppConfig.PREF_DNS_HOSTS,
AppConfig.PREF_DELAY_TEST_URL,
AppConfig.PREF_LOCAL_DNS_PORT,
AppConfig.PREF_SOCKS_PORT,

View File

@@ -77,6 +77,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"

View File

@@ -1,40 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:paddingStart="@dimen/padding_start"
android:paddingEnd="@dimen/padding_end"
tools:context=".ui.LogcatActivity">
<ProgressBar
android:id="@+id/pb_waiting"
style="@android:style/Widget.DeviceDefault.ProgressBar"
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
android:layout_height="match_parent">
<ScrollView
android:id="@+id/sv_logcat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:fillViewport="false"
android:foregroundGravity="bottom">
<TextView
android:id="@+id/tv_logcat"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:maxLines="65536"
android:textAppearance="?android:attr/textAppearanceSmall" />
</ScrollView>
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</RelativeLayout>

View File

@@ -54,6 +54,7 @@
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"

View File

@@ -1,4 +1,5 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -16,18 +17,16 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:checked="true" />
android:checked="true"
app:theme="@style/BrandedSwitch" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@id/switch_start_service"
android:layout_toLeftOf="@id/switch_start_service"
android:text="@string/tasker_start_service"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/layout_margin_spacing">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/log_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
</LinearLayout>

View File

@@ -44,70 +44,76 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_margin_spacing"
android:lines="1"
android:lines="2"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="@dimen/sub_height"
android:gravity="center"
android:orientation="vertical"
android:paddingStart="@dimen/padding_start"
android:paddingEnd="@dimen/padding_end">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_margin_spacing"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/layout_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing">
<ImageView
android:layout_width="@dimen/png_height"
android:layout_height="@dimen/png_height"
app:srcCompat="@drawable/ic_share_24dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:nextFocusLeft="@+id/info_container"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing">
<ImageView
android:layout_width="@dimen/png_height"
android:layout_height="@dimen/png_height"
app:srcCompat="@drawable/ic_edit_24dp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_margin_top_height"
android:orientation="horizontal">
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/chk_enable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sub_setting_enable"
app:theme="@style/BrandedSwitch" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="@dimen/sub_height"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/layout_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing">
<ImageView
android:layout_width="@dimen/png_height"
android:layout_height="@dimen/png_height"
app:srcCompat="@drawable/ic_share_24dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:nextFocusLeft="@+id/info_container"
android:orientation="vertical"
android:padding="@dimen/layout_margin_spacing">
<ImageView
android:layout_width="@dimen/png_height"
android:layout_height="@dimen/png_height"
app:srcCompat="@drawable/ic_edit_24dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@@ -5,10 +5,10 @@
android:id="@+id/del_config"
android:icon="@drawable/ic_delete_24dp"
android:title="@string/menu_item_del_config"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
<item
android:id="@+id/save_config"
android:icon="@drawable/ic_action_done"
android:title="@string/menu_item_save_config"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
</menu>

View File

@@ -5,10 +5,10 @@
android:id="@+id/add_config"
android:icon="@drawable/ic_add_24dp"
android:title="@string/menu_item_add_config"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
<item
android:id="@+id/sub_update"
android:icon="@drawable/ic_restore_24dp"
android:title="@string/title_sub_update"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
</menu>

View File

@@ -24,5 +24,5 @@
android:id="@+id/download_file"
android:icon="@drawable/ic_cloud_download_24dp"
android:title="@string/menu_item_download_file"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
</menu>

View File

@@ -6,7 +6,7 @@
android:icon="@drawable/ic_description_24dp"
android:title="@string/menu_item_search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
<item
android:id="@+id/select_all"
android:icon="@drawable/ic_select_all_24dp"

View File

@@ -1,14 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/search_view"
android:icon="@drawable/ic_outline_filter_alt_24"
android:title="@string/menu_item_search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always|collapseActionView" />
<item
android:id="@+id/clear_all"
android:icon="@drawable/ic_delete_24dp"
android:title="@string/logcat_clear"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
<item
android:id="@+id/copy_all"
android:icon="@drawable/ic_copy"
android:title="@string/logcat_copy"
app:showAsAction="always" />
app:showAsAction="ifRoom" />
</menu>

View File

@@ -55,7 +55,7 @@
<item
android:title="@string/menu_item_import_config_custom"
app:showAsAction="always">
app:showAsAction="ifRoom">
<menu>
<item
android:id="@+id/import_config_custom_clipboard"

View File

@@ -5,10 +5,10 @@
android:id="@+id/scan_code"
android:icon="@drawable/ic_scan_24dp"
android:title=""
app:showAsAction="always" />
app:showAsAction="ifRoom" />
<item
android:id="@+id/select_photo"
android:icon="@drawable/ic_image_24dp"
android:title=""
app:showAsAction="always" />
app:showAsAction="ifRoom" />
</menu>

View File

@@ -8,6 +8,7 @@
<string name="navigation_drawer_close">إغلاق درج التنقل</string>
<string name="migration_success">نجحت عملية ترحيل البيانات!</string>
<string name="migration_fail">فشلت عملية ترحيل البيانات!</string>
<string name="pull_down_to_refresh">Please pull down to refresh!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">إيقاف</string>
@@ -176,10 +177,14 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (IPv4/v6 فقط)</string>
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
<string name="title_pref_domestic_dns">DNS المحلي (اختياري)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">DNS hosts (Format: domain:address,…)</string>
<string name="summary_pref_dns_hosts">domain:address,…</string>
<string name="title_pref_delay_test_url">True delay test url (http/https)</string>
<string name="summary_pref_delay_test_url">Url</string>
@@ -320,4 +325,10 @@
<item>داكن</item>
</string-array>
<string-array name="vpn_bypass_lan">
<item>Follow config</item>
<item>Bypass</item>
<item>Not Bypass</item>
</string-array>
</resources>

View File

@@ -8,6 +8,7 @@
<string name="navigation_drawer_close">নেভিগেশন ড্রয়ার বন্ধ করুন</string>
<string name="migration_success">ডেটা স্থানান্তর সফল!</string>
<string name="migration_fail">ডেটা স্থানান্তর ব্যর্থ!</string>
<string name="pull_down_to_refresh">Please pull down to refresh!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">বন্ধ করুন</string>
@@ -176,10 +177,14 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (শুধুমাত্র IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
<string name="title_pref_domestic_dns">ঘরোয়া DNS (ঐচ্ছিক)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">DNS hosts (Format: domain:address,…)</string>
<string name="summary_pref_dns_hosts">domain:address,…</string>
<string name="title_pref_delay_test_url">সঠিক বিলম্ব পরীক্ষা ইউআরএল (http/https)</string>
<string name="summary_pref_delay_test_url">ইউআরএল</string>
@@ -324,5 +329,10 @@
<item>ইরান হোয়াইটলিস্ট</item>
</string-array>
<string-array name="vpn_bypass_lan">
<item>Follow config</item>
<item>Bypass</item>
<item>Not Bypass</item>
</string-array>
</resources>

View File

@@ -8,6 +8,7 @@
<string name="navigation_drawer_close">بستن نومگه کشاری</string>
<string name="migration_success">مووفقیت من جاگورویی داده</string>
<string name="migration_fail">جاگورویی داده ٱنجوم نگرؽڌ</string>
<string name="pull_down_to_refresh">Please pull down to refresh!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">واڌاشتن</string>
@@ -40,16 +41,16 @@
<string name="menu_item_import_config_custom_url">کانفیگ سفارشین ز آدرس اینترنتی و من بیار</string>
<string name="menu_item_import_config_custom_url_scan">نشۊوی اینترنتی اسکن کانفیگ سفارشین بزݩ</string>
<string name="del_config_comfirm">پاک بۊ؟</string>
<string name="del_invalid_config_comfirm">پؽش ز پاک کردن کانفیگ نا موئتبر قوۊل کوݩ! پاک کردن کانفیگن قوۊل اکۊنی؟</string>
<string name="del_invalid_config_comfirm">پؽش ز پاک کردن کانفیگ نا موئتبر واجۊری کوݩ! پاک کردن کانفیگن قوۊل اکۊنی؟</string>
<string name="server_lab_remarks">نیشتنا</string>
<string name="server_lab_address">آدرس</string>
<string name="server_lab_port">پورت</string>
<string name="server_lab_id">نوم من توری</string>
<string name="server_lab_alterid">alterId</string>
<string name="server_lab_alterid">شناسه جایگۊزین</string>
<string name="server_lab_security">ٱمنیت</string>
<string name="server_lab_network">شبکه</string>
<string name="server_lab_more_function">جاگورو</string>
<string name="server_lab_head_type">نوء head</string>
<string name="server_lab_head_type">نوء سر بلگ</string>
<string name="server_lab_mode_type">هالت gRPC</string>
<string name="server_lab_request_host">هاست</string>
<string name="server_lab_request_host_http">هاست http</string>
@@ -58,14 +59,14 @@
<string name="server_lab_request_host_xhttp">هاست xhttp</string>
<string name="server_lab_request_host_h2">هاست h2</string>
<string name="server_lab_request_host_quic">ٱمنیت QUIC</string>
<string name="server_lab_request_host_grpc">اختیار gRPC</string>
<string name="server_lab_request_host_grpc">Authority gRPC</string>
<string name="server_lab_path">تور</string>
<string name="server_lab_path_ws">تور ws</string>
<string name="server_lab_path_httpupgrade">تور httpupgrade</string>
<string name="server_lab_path_xhttp">تور xhttp</string>
<string name="server_lab_path_h2">تور h2</string>
<string name="server_lab_path_quic">کیلیت QUIC</string>
<string name="server_lab_path_kcp">سید kcp</string>
<string name="server_lab_path_ws">تور WS</string>
<string name="server_lab_path_httpupgrade">تور HTTPUpgrade</string>
<string name="server_lab_path_xhttp">تور XHTTP</string>
<string name="server_lab_path_h2">تور H2</string>
<string name="server_lab_path_quic">تور QUIC</string>
<string name="server_lab_path_kcp">KCP seed</string>
<string name="server_lab_path_grpc">نوم خدمات gRPC</string>
<string name="server_lab_stream_security">TLS</string>
<string name="server_lab_stream_fingerprint" translatable="false">Fingerprint</string>
@@ -82,12 +83,12 @@
<string name="server_lab_flow">جریان</string>
<string name="server_lab_public_key">کیلیت پوی وولاتی</string>
<string name="server_lab_preshared_key">کیلیت رمز ناهاڌن ازاف (اختیاری)</string>
<string name="server_lab_short_id">ShortId</string>
<string name="server_lab_short_id">ShortID</string>
<string name="server_lab_spider_x">SpiderX</string>
<string name="server_lab_secret_key">کیلیت سیخومی</string>
<string name="server_lab_reserved">Reserved(اختیاری، وا کاما ز یک جوڌا ابۊن)</string>
<string name="server_lab_local_address">آدرس مهلی (اختیاری IPv4/IPv6، وا کاما ز یک جوڌا ابۊن)</string>
<string name="server_lab_local_mtu">Mtu(اختیاری، خوتکار 1420)</string>
<string name="server_lab_local_mtu">Mtu(اختیاری، پؽش فرز 1420)</string>
<string name="toast_success">وا مووفقیت ٱنجوم وابی</string>
<string name="toast_failure">شکست خرد</string>
<string name="toast_none_data">هیچ داده ای وۊجۊڌ نڌاره</string>
@@ -107,7 +108,7 @@
<string name="toast_asset_copy_failed">لف گیری فایل ٱنجوم نوابی، ز ی برنومه دؽوۉداری فایل هیاری بگرین</string>
<string name="menu_item_add_asset">ازاف کردن دارایی</string>
<string name="menu_item_add_file">ازاف کردن فایل</string>
<string name="menu_item_add_url">ازاف کردن آدرس اینترنتی</string>
<string name="menu_item_add_url">ازاف کردن لینگ</string>
<string name="menu_item_scan_qrcode">اسکن QRcode</string>
<string name="title_url">آدرس اینترنتی</string>
<string name="menu_item_download_file">دانلود فایلا</string>
@@ -115,12 +116,12 @@
<string name="msg_file_not_found">فایلن نجوست</string>
<string name="msg_remark_is_duplicate">ائزارات ز زیتر بیڌسۉݩ</string>
<string name="toast_action_not_allowed">ای کار ممنۊ هڌ</string>
<string name="server_obfs_password">رزم Obfs</string>
<string name="server_obfs_password">رزم obfs</string>
<string name="server_lab_port_hop">پورت گوم (درگا سرورن ز نۊ هؽل اکونه)</string>
<string name="server_lab_port_hop_interval">فاسله پورت گوم (سانیه)</string>
<string name="server_lab_stream_pinsha256">pinSHA256</string>
<string name="server_lab_xhttp_mode">هالت XHTTP</string>
<string name="server_lab_xhttp_extra">XHTTP قلوه خام JSON، قالوو: { XHTTPObject }</string>
<string name="server_lab_xhttp_extra">XHTTP Extra خام JSON، قالوو: { XHTTPObject }</string>
<!-- PerAppProxyActivity -->
<string name="msg_dialog_progress">هون بار ونی بۊ</string>
@@ -176,16 +177,20 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (تینا IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">VPN ز شبکه مهلی اگوڌرته؟</string>
<string name="title_pref_domestic_dns">DNS منی (اختیاری)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">DNS هاست موستقیم (قالوو: دامنه: آدرس،...)</string>
<string name="summary_pref_dns_hosts">دامنه:آدرس،...</string>
<string name="title_pref_delay_test_url">آدرس اینترنتی آزمایش تئخیر واقعی (http/https)</string>
<string name="summary_pref_delay_test_url">نشۊوی اینترنتی</string>
<string name="title_pref_proxy_sharing_enabled">هشتن منپیزا ز LAN</string>
<string name="title_pref_proxy_sharing_enabled">هشتن منپیزا ز شبکه مهلی</string>
<string name="summary_pref_proxy_sharing_enabled">پوی دسگایل ترن وا آدرس IP ایسا، ز ر socks/http و پروکسی منپیز بۊن، تینا من شبکه قابل اعتماد فعال بۊ تا ز منپیز ؛یر موجاز جلو گری بۊ.</string>
<string name="toast_warning_pref_proxysharing_short">منپیزا ز LAN ن موجار کۊنین، موتمعن بۊین ک من ی شبکه قابل ائتماڌ هڌین.</string>
<string name="toast_warning_pref_proxysharing_short">منپیزا ز شبکه مهلی ن موجار کۊنین، موتمعن بۊین ک من ی شبکه قابل ائتماڌ هڌین.</string>
<string name="title_pref_allow_insecure">اجازه نا ٱمن</string>
<string name="summary_pref_allow_insecure">مجال و کار بردن TLS ب تۉر پؽش فرز، موجوز نا ٱمن فعال هڌ.</string>
@@ -228,7 +233,7 @@
<string name="title_core_loglevel">سئت داسووا</string>
<string name="title_mode">هالت</string>
<string name="title_mode_help">سی هیاری بیشتر ری ای هؽل بزݩ</string>
<string name="title_mode_help">سی دووسمندیا وو هیاری بیشتر، ری ای هؽل بزݩ</string>
<string name="title_language">زۉݩ</string>
<string name="title_ui_settings">سامووا رابت منتوری</string>
<string name="title_pref_ui_mode_night">سامووا هالت رابت منتوری</string>
@@ -244,12 +249,12 @@
<string name="title_sub_setting">سامووا جرگه اشتراک</string>
<string name="sub_setting_remarks">نیشتنا</string>
<string name="sub_setting_url">نشۊوی اینترنتی اختیاری</string>
<string name="sub_setting_filter">نیشتنا فیلتر مئمۊلی</string>
<string name="sub_setting_filter">نوم موستعار فیلتر</string>
<string name="sub_setting_enable">فعال بیڌن ورۊ کردن</string>
<string name="sub_auto_update">فعال بیڌن ورۊ کردن خوتکار</string>
<string name="sub_setting_pre_profile">نیشتنا پروکسی پؽشی</string>
<string name="sub_setting_next_profile">نیشتنا پروکسی نیایی</string>
<string name="sub_setting_pre_profile_tip">نیشتنا هڌسۉݩ وو هرف نارن</string>
<string name="sub_setting_pre_profile">نوم موستعار پروکسی دیندایی</string>
<string name="sub_setting_next_profile">نوم موستعار پروکسی نیایی</string>
<string name="sub_setting_pre_profile_tip">موتمعن بۊ ک نوم موستعار هڌس وو جۊرس نی</string>
<string name="title_sub_update">ورۊ کردن اشتراک جرگه سکویی</string>
<string name="title_ping_all_server">Tcping کانفیگا جرگه سکویی</string>
<string name="title_real_ping_all_server">تئخیر واقعی کانفیگا جرگه سکویی</string>
@@ -335,4 +340,10 @@
<item>نومگه اسبؽڌ ایران</item>
</string-array>
</resources>
<string-array name="vpn_bypass_lan">
<item>پؽش فرز کانفیگ</item>
<item>دور زیڌه بۊ</item>
<item>دور زیڌه نبۊ</item>
</string-array>
</resources>

View File

@@ -8,6 +8,7 @@
<string name="navigation_drawer_close">بستن منو کشویی</string>
<string name="migration_success">موفقیت در انتقال داده</string>
<string name="migration_fail">انتقال داده انجام نشد!</string>
<string name="pull_down_to_refresh">Please pull down to refresh!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">توقف</string>
@@ -40,36 +41,36 @@
<string name="menu_item_import_config_custom_url">کانفیگ سفارشی را از طریق نشانی اینترنتی وارد کنید</string>
<string name="menu_item_import_config_custom_url_scan">نشانی اینترنتی اسکن کانفیگ سفارشی را وارد کنید</string>
<string name="del_config_comfirm">حذف شود؟</string>
<string name="del_invalid_config_comfirm">لطفا قبل از حذف کانفیگ نامعتبر تایید کنید! حذف کانفیگ را تایید می کنید؟</string>
<string name="del_invalid_config_comfirm">لطفا قبل از حذف کانفیگ نامعتبر بررسی کنید! حذف کانفیگ را تایید می کنید؟</string>
<string name="server_lab_remarks">ملاحظات</string>
<string name="server_lab_address">نشانی</string>
<string name="server_lab_port">پورت</string>
<string name="server_lab_id">شناسه</string>
<string name="server_lab_alterid">alterId</string>
<string name="server_lab_alterid">شناسه جایگزین</string>
<string name="server_lab_security">امنیت</string>
<string name="server_lab_network">شبکه</string>
<string name="server_lab_more_function">انتقال</string>
<string name="server_lab_head_type">نوع HEAD</string>
<string name="server_lab_mode_type">حالت GRPC</string>
<string name="server_lab_request_host">HOST</string>
<string name="server_lab_request_host_http">HTTP HOST</string>
<string name="server_lab_request_host_ws">WS HOST</string>
<string name="server_lab_request_host_httpupgrade">HTTPUPGRADE HOST</string>
<string name="server_lab_request_host_xhttp">XHTTP HOST</string>
<string name="server_lab_request_host_h2">H2 HOST</string>
<string name="server_lab_head_type">نوع سربرگ</string>
<string name="server_lab_mode_type">حالت gRPC</string>
<string name="server_lab_request_host">هاست</string>
<string name="server_lab_request_host_http">هاست HTTP</string>
<string name="server_lab_request_host_ws">هاست WS</string>
<string name="server_lab_request_host_httpupgrade">هاست HTTPUpgrade</string>
<string name="server_lab_request_host_xhttp">هاست XHTTP</string>
<string name="server_lab_request_host_h2">هاست H2</string>
<string name="server_lab_request_host_quic">QUIC security</string>
<string name="server_lab_request_host_grpc">GRPC Authority</string>
<string name="server_lab_path">PATH</string>
<string name="server_lab_path_ws">WS PATH</string>
<string name="server_lab_path_httpupgrade">HTTPUPGRADE PATH</string>
<string name="server_lab_path_xhttp">XHTTP PATH</string>
<string name="server_lab_path_h2">H2 PATH</string>
<string name="server_lab_path_quic">QUIC key</string>
<string name="server_lab_path_kcp">KCP SEED</string>
<string name="server_lab_path_grpc">GRPC SERVICENAME</string>
<string name="server_lab_request_host_grpc">gRPC Authority</string>
<string name="server_lab_path">مسیر</string>
<string name="server_lab_path_ws">مسیر WS</string>
<string name="server_lab_path_httpupgrade">مسیر HTTPUpgrade</string>
<string name="server_lab_path_xhttp">مسیر XHTTP</string>
<string name="server_lab_path_h2">مسیر H2</string>
<string name="server_lab_path_quic">مسیر QUIC</string>
<string name="server_lab_path_kcp">KCP seed</string>
<string name="server_lab_path_grpc">gRPC ServiceName</string>
<string name="server_lab_stream_security">TLS</string>
<string name="server_lab_stream_fingerprint">اثرانگشت</string>
<string name="server_lab_stream_alpn">AlPN</string>
<string name="server_lab_stream_alpn">Alpn</string>
<string name="server_lab_allow_insecure">اعطای مجوز ناامن</string>
<string name="server_lab_sni">SNI</string>
<string name="server_lab_address3">نشانی</string>
@@ -82,12 +83,12 @@
<string name="server_lab_flow">جریان</string>
<string name="server_lab_public_key">کلید عمومی</string>
<string name="server_lab_preshared_key">کلید رمزگذاری اضافی (اختیاری)</string>
<string name="server_lab_short_id">SHORTID</string>
<string name="server_lab_spider_x">SPIDERX</string>
<string name="server_lab_short_id">ShortID</string>
<string name="server_lab_spider_x">SpiderX</string>
<string name="server_lab_secret_key">کلید خصوصی</string>
<string name="server_lab_reserved">Reserved (اختیاری)</string>
<string name="server_lab_local_address">آدرس محلی IPV4(اختیاری)</string>
<string name="server_lab_local_mtu">MTU (اختیاری، پیش فرض: 1420)</string>
<string name="server_lab_reserved">Reserved (اختیاری، جدا شده با کاما)</string>
<string name="server_lab_local_address">آدرس محلی IPV4 (اختیاری)</string>
<string name="server_lab_local_mtu">MTU (اختیاری، پیشفرض 1420)</string>
<string name="toast_success">با موفقیت انجام شد</string>
<string name="toast_failure">شکست</string>
<string name="toast_none_data">هیچ داده ای وجود ندارد</string>
@@ -103,19 +104,19 @@
<string name="toast_insecure_url_protocol">لطفاً از آدرس اشتراک پروتکل HTTP ناامن استفاده نکنید</string>
<string name="server_lab_need_inbound">اطمینان حاصل کنید که پورت ورودی با تنظیمات مطابقت دارد</string>
<string name="toast_malformed_josn">کانفیگ درست نیست</string>
<string name="server_lab_request_host6">میزبان (SNI) (اختیاری)</string>
<string name="server_lab_request_host6">هاست (SNI) (اختیاری)</string>
<string name="toast_asset_copy_failed">کپی فایل انجام نشد، لطفا از برنامه مدیریت فایل استفاده کنید</string>
<string name="menu_item_add_file">افزودن فایل ها</string>
<string name="menu_item_scan_qrcode">اسکن QRcode</string>
<string name="title_url">URL</string>
<string name="menu_item_download_file">دانلود فایل‌ ها</string>
<string name="toast_action_not_allowed">این عمل ممنوع است</string>
<string name="server_obfs_password">رمز عبور OBFS</string>
<string name="server_obfs_password">رمز عبور obfs</string>
<string name="server_lab_port_hop">پورت پرش (درگاه سرور را بازنویسی می کند)</string>
<string name="server_lab_port_hop_interval">فاصله پورت پرش (ثانیه)</string>
<string name="server_lab_stream_pinsha256">PINSHA256</string>
<string name="server_lab_stream_pinsha256">pinSHA256</string>
<string name="server_lab_xhttp_mode">حالت XHTTP</string>
<string name="server_lab_xhttp_extra">جیسون خام XHTTP EXTRA، فرمت: { XHTTPObject }</string>
<string name="server_lab_xhttp_extra">خام JSON XHTTP Extra، قالب: { XHTTPObject }</string>
<!-- PerAppProxyActivity -->
<string name="title_user_asset_add_url">آدرس اینترنتی را اضافه کنید</string>
@@ -125,7 +126,7 @@
<string name="menu_item_search">جستجو</string>
<string name="menu_item_select_all">انتخاب همه</string>
<string name="msg_enter_keywords">کلیدواژه‌ ها را وارد کنید</string>
<string name="switch_bypass_apps_mode">حالت Bypass</string>
<string name="switch_bypass_apps_mode">حالت دور زدن</string>
<string name="menu_item_select_proxy_app">انتخاب خودکار پروکسی برنامه</string>
<string name="msg_downloading_content">در حال دانلود محتوا</string>
<string name="menu_item_export_proxy_app">خروجی گرفتن در کلیپ‌ بورد</string>
@@ -136,7 +137,7 @@
<string name="title_advanced">تنظیمات پیشرفته</string>
<string name="title_vpn_settings">تنظیمات VPN</string>
<string name="title_pref_per_app_proxy">پروکسی به تفکیک برنامه</string>
<string name="summary_pref_per_app_proxy">عمومی: برنامه بررسی شده پروکسی است، اتصال مستقیم بدون بررسی است. \nحالت bypass: برنامه بررسی شده مستقیما متصل است، پراکسی بررسی نشده است. \nگزینهای برای انتخاب خودکار پروکسی برنامه در منو است.</string>
<string name="summary_pref_per_app_proxy">عمومی: برنامه بررسی شده پروکسی است، اتصال مستقیم بدون بررسی است. \nحالت دور زدن: برنامه بررسی شده مستقیما متصل است، پراکسی بررسی نشده است. \nگزینهای برای انتخاب خودکار پروکسی برنامه در منو است.</string>
<string name="title_pref_is_booted">اتصال خودکار هنگام راه اندازی</string>
<string name="summary_pref_is_booted">هنگام راه اندازی به طور خودکار به سرور انتخابی متصل می شود که ممکن است ناموفق باشد.</string>
@@ -153,12 +154,12 @@
</string-array>
<string name="title_pref_speed_enabled">فعال کردن نمایش سرعت</string>
<string name="summary_pref_speed_enabled">نمایش سرعت فعلی در قسمت آگاه‌سازی. \nآیکون آگاه‌سازی بر اساس استفاده تغییر می‌کند.</string>
<string name="summary_pref_speed_enabled">نمایش سرعت فعلی در قسمت اعلان. \nآیکون اعلان بر اساس استفاده تغییر می‌کند.</string>
<string name="title_pref_sniffing_enabled">فعال کردن SNIFFING</string>
<string name="summary_pref_sniffing_enabled">دامنه SNIFF را از بسته امتحان کنید (پیشفرض روشن)</string>
<string name="title_pref_route_only_enabled">فعال کردن ROUTEONLY</string>
<string name="summary_pref_route_only_enabled">از نام دامنه SNIFFED فقط برای مسیریابی استفاده کنید و آدرس مورد نظر را به عنوان آدرس IP نگه دارید.</string>
<string name="title_pref_sniffing_enabled">فعال کردن تجزیه و تحلیل بسته ها (Sniffing)</string>
<string name="summary_pref_sniffing_enabled">استفاده از تشخیص نام دامنه (Sniff) در بسته ها (به طور پیش فرض فعال است)</string>
<string name="title_pref_route_only_enabled">فعال کردن دامنه فقط مسیر یابی (RouteOnly)</string>
<string name="summary_pref_route_only_enabled">از نام دامنه (Snnifed) فقط برای مسیریابی استفاده کنید و آدرس مقصد را به عنوان IP ذخیره کنید.</string>
<string name="title_pref_local_dns_enabled">فعال کردن DNS محلی</string>
@@ -174,16 +175,20 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (فقط IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">آیا VPN از شبکه محلی عبور می کند؟</string>
<string name="title_pref_domestic_dns">DNS داخلی (اختیاری)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">DNS مستقیم هاست (فرمت: دامنه:آدرس،…)</string>
<string name="summary_pref_dns_hosts">دامنه:آدرس،…</string>
<string name="title_pref_delay_test_url">آدرس اینترنتی آزمایش تاخیر واقعی کانفیگ ها (HTTP/HTTPS)</string>
<string name="summary_pref_delay_test_url">URL</string>
<string name="title_pref_proxy_sharing_enabled">اجازه اتصالات از طریق LAN</string>
<string name="summary_pref_proxy_sharing_enabled">سایر دستگاهها میتوانند با آدرس آیپی شما از طریق پراکسی محلی به پروکسی متصل شوند، فقط در شبکه قابل اعتماد فعال شود تا از اتصال غیرمجاز جلوگیری شود.</string>
<string name="toast_warning_pref_proxysharing_short">اتصالات از طریق LAN را مجاز کنید، مطمئن شوید که در یک شبکه قابل اعتماد هستید</string>
<string name="title_pref_proxy_sharing_enabled">اجازه اتصالات از طریق شبکه محلی</string>
<string name="summary_pref_proxy_sharing_enabled">سایر دستگاه ها می توانند با استفاده از آدرس آیپی شما برای استفاده از یک پروکسی محلی متصل شوند. فقط در یک شبکه قابل اعتماد برای جلوگیری از اتصالات غیرمجاز استفاده کنید.</string>
<string name="toast_warning_pref_proxysharing_short">اتصالات از طریق شبکه محلی را مجاز کنید، مطمئن شوید که در یک شبکه قابل اعتماد هستید.</string>
<string name="title_pref_allow_insecure">اعطای مجوز ناامن</string>
<string name="summary_pref_allow_insecure">هنگام استفاده از TLS، به طور پیش‌ فرض مجوز ناامن فعال است.</string>
@@ -225,7 +230,7 @@
<string name="title_pref_auto_update_interval">فاصله به‌ روزرسانی خودکار ( حداقل مقدار ، 15 دقیقه )</string>
<string name="title_core_loglevel">سطح گزارشات</string>
<string name="title_mode">حالت</string>
<string name="title_mode_help">برای راهنمایی بیشتر روی این متن، کلیک کنید</string>
<string name="title_mode_help">برای اطلاعات و راهنمایی بیشتر، روی این متن کلیک کنید</string>
<string name="title_language">زبان</string>
<string name="title_ui_settings">تنظیمات رابط کاربری</string>
<string name="title_pref_ui_mode_night">تنظیمات حالت رابط کاربری</string>
@@ -241,12 +246,12 @@
<string name="title_sub_setting">تنظیمات گروه‌ اشتراک</string>
<string name="sub_setting_remarks">ملاحظات</string>
<string name="sub_setting_url">نشانی اینترنتی اختیاری</string>
<string name="sub_setting_filter">REMARKS REGULAR FILTER</string>
<string name="sub_setting_filter">نام مستعار فیلتر</string>
<string name="sub_setting_enable">فعال کردن به‌روزرسانی</string>
<string name="sub_auto_update">فعال سازی به‌روزرسانی خودکار</string>
<string name="sub_setting_pre_profile">Previous proxy remarks</string>
<string name="sub_setting_next_profile">Next proxy remarks</string>
<string name="sub_setting_pre_profile_tip">The remarks exists and is unique</string>
<string name="sub_setting_pre_profile">نام مستعار پروکسی قبلی</string>
<string name="sub_setting_next_profile">نام مستعار پروکسی بعدی</string>
<string name="sub_setting_pre_profile_tip">لطفاً مطمئن شوید که نام مستعار وجود دارد و منحصر به فرد است</string>
<string name="title_sub_update">به‌روزرسانی گروه فعلی اشتراک</string>
<string name="title_ping_all_server">TCPING کانفیگ های گروه فعلی</string>
<string name="title_real_ping_all_server">تاخیر واقعی کانفیگ های گروه فعلی</string>
@@ -333,4 +338,10 @@
<item>ایران</item>
</string-array>
<string-array name="vpn_bypass_lan">
<item>پیش فرض کانفیگ</item>
<item>دور زده شود</item>
<item>دور زده نشود</item>
</string-array>
</resources>

View File

@@ -7,6 +7,7 @@
<string name="navigation_drawer_close">Закрыть панель навигации</string>
<string name="migration_success">Успешный перенос данных!</string>
<string name="migration_fail">Перенос данных не выполнен!</string>
<string name="pull_down_to_refresh">Please pull down to refresh!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">Остановить</string>
@@ -175,15 +176,19 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (только IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">VPN пропускает LAN</string>
<string name="title_pref_domestic_dns">Внутренняя DNS (необязательно)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">Узлы DNS (формат: домен:адрес,…)</string>
<string name="summary_pref_dns_hosts">домен:адрес,…</string>
<string name="title_pref_delay_test_url">Сервис проверки времени отклика (HTTP/HTTPS)</string>
<string name="summary_pref_delay_test_url">URL</string>
<string name="title_pref_proxy_sharing_enabled">Разрешать подключения из LAN</string>
<string name="summary_pref_proxy_sharing_enabled">Другие устройства могут подключаться, используя ваш IP-адрес, чтобы использовать прокси по протоколам SOCKS/HTTP. Используйте только в доверенной сети, чтобы избежать несанкционированного подключения.</string>
<string name="summary_pref_proxy_sharing_enabled">Другие устройства могут подключаться, используя ваш IP-адрес, чтобы использовать локальный прокси. Используйте только в доверенной сети, чтобы избежать несанкционированного подключения.</string>
<string name="toast_warning_pref_proxysharing_short">Доступ из LAN разрешён, убедитесь, что вы находитесь в доверенной сети</string>
<string name="title_pref_allow_insecure">Разрешать небезопасные</string>
@@ -289,7 +294,7 @@
<string name="connection_test_pending">Проверить подключение</string>
<string name="connection_test_testing">Проверка…</string>
<string name="connection_test_testing_count">Проверено профилей: %d</string>
<string name="connection_test_testing_count">Проверка профилей: %d</string>
<string name="connection_test_available">Успешно: HTTP-соединение заняло %d мс</string>
<string name="connection_test_error">Сбой проверки интернет-соединения: %s</string>
<string name="connection_test_fail">Интернет недоступен</string>
@@ -334,4 +339,10 @@
<item>Белый список Ирана</item>
</string-array>
<string-array name="vpn_bypass_lan">
<item>Как в профиле</item>
<item>Пропускает</item>
<item>Не пропускает</item>
</string-array>
</resources>

View File

@@ -7,6 +7,7 @@
<string name="navigation_drawer_close">Đóng Menu ứng dụng</string>
<string name="migration_success">Đã chuyển dữ liệu!</string>
<string name="migration_fail">Không thể chuyển dữ liệu!</string>
<string name="pull_down_to_refresh">Please pull down to refresh!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">Ngắt kết nối v2rayNG</string>
@@ -175,10 +176,14 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (Chỉ IPv4 / IPv6)</string>
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
<string name="title_pref_domestic_dns">DNS nội địa (Không bắt buộc)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">DNS hosts (Format: domain:address,…)</string>
<string name="summary_pref_dns_hosts">domain:address,…</string>
<string name="title_pref_delay_test_url">URL kiểm tra độ trễ thực (HTTP / HTTPS)</string>
<string name="summary_pref_delay_test_url">URL</string>
@@ -321,4 +326,10 @@
<string name="title_pref_fragment_interval">Fragment Interval (min-max)</string>
<string name="title_pref_fragment_enabled">Enable Fragment</string>
<string-array name="vpn_bypass_lan">
<item>Follow config</item>
<item>Bypass</item>
<item>Not Bypass</item>
</string-array>
</resources>

View File

@@ -7,6 +7,7 @@
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="migration_success">数据迁移成功!</string>
<string name="migration_fail">数据迁移失败啦!</string>
<string name="pull_down_to_refresh">请下拉刷新!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">停止</string>
@@ -172,10 +173,14 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (仅支持 IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">VPN是否绕过局域网</string>
<string name="title_pref_domestic_dns">境内DNS (可选)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">DNS hosts (格式: 域名:地址,…)</string>
<string name="summary_pref_dns_hosts">domain:address,…</string>
<string name="title_pref_delay_test_url">真连接延迟测试网址 (http/https)</string>
<string name="summary_pref_delay_test_url">Url</string>
@@ -325,4 +330,10 @@
<item>伊朗(Iran)</item>
</string-array>
<string-array name="vpn_bypass_lan">
<item>跟随配置文件</item>
<item>绕过</item>
<item>不绕过</item>
</string-array>
</resources>

View File

@@ -7,6 +7,7 @@
<string name="navigation_drawer_close">關閉導覽匣</string>
<string name="migration_success">資料遷移成功!</string>
<string name="migration_fail">資料遷移失敗!</string>
<string name="pull_down_to_refresh">請下拉刷新!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">停止</string>
@@ -174,9 +175,10 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (僅支援 IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">VPN是否繞過區域網</string>
<string name="title_pref_domestic_dns">國內 DNS (可選)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">DNS hosts (格式: 網域:位址,…)</string>
<string name="summary_pref_dns_hosts">domain:address,…</string>
<string name="title_pref_delay_test_url">真連線延遲測試網址 (http/https)</string>
<string name="summary_pref_delay_test_url">Url</string>
@@ -327,4 +329,10 @@
<item>伊朗(Iran)</item>
</string-array>
<string-array name="vpn_bypass_lan">
<item>跟隨設定檔</item>
<item>繞過</item>
<item>不繞過</item>
</string-array>
</resources>

View File

@@ -211,4 +211,11 @@
<item>stream-up</item>
<item>stream-one</item>
</string-array>
<string-array name="vpn_bypass_lan_value" translatable="false">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
</resources>

View File

@@ -8,6 +8,7 @@
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="migration_success">Data migration success!</string>
<string name="migration_fail">Data migration failed!</string>
<string name="pull_down_to_refresh">Please pull down to refresh!</string>
<!-- Notifications -->
<string name="notification_action_stop_v2ray">Stop</string>
@@ -178,10 +179,14 @@
<string name="summary_pref_remote_dns">DNS</string>
<string name="title_pref_vpn_dns">VPN DNS (only IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
<string name="title_pref_domestic_dns">Domestic DNS (Optional)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_dns_hosts">DNS hosts (Format: domain:address,…)</string>
<string name="summary_pref_dns_hosts">domain:address,…</string>
<string name="title_pref_delay_test_url">True delay test url (http/https)</string>
<string name="summary_pref_delay_test_url">Url</string>
@@ -337,4 +342,10 @@
<item>Iran Whitelist</item>
</string-array>
<string-array name="vpn_bypass_lan">
<item>Follow config</item>
<item>Bypass</item>
<item>Not Bypass</item>
</string-array>
</resources>

View File

@@ -49,6 +49,14 @@
android:key="pref_vpn_dns"
android:summary="@string/summary_pref_remote_dns"
android:title="@string/title_pref_vpn_dns" />
<ListPreference
android:defaultValue="0"
android:entries="@array/vpn_bypass_lan"
android:entryValues="@array/vpn_bypass_lan_value"
android:key="pref_vpn_bypass_lan"
android:summary="%s"
android:title="@string/title_pref_vpn_bypass_lan" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/title_ui_settings">
@@ -190,6 +198,11 @@
android:summary="@string/summary_pref_domestic_dns"
android:title="@string/title_pref_domestic_dns" />
<EditTextPreference
android:key="pref_dns_hosts"
android:summary="@string/summary_pref_dns_hosts"
android:title="@string/title_pref_dns_hosts" />
<EditTextPreference
android:key="pref_delay_test_url"
android:summary="@string/summary_pref_delay_test_url"

View File

@@ -7,7 +7,7 @@ plugins {
buildscript {
dependencies {
classpath(libs.oss.licenses.plugin)
classpath(libs.gradle.license.plugin)
}
}

View File

@@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects

View File

@@ -1,5 +1,7 @@
[versions]
agp = "8.7.2"
agp = "8.7.3"
desugar_jdk_libs = "2.1.4"
gradleLicensePlugin = "0.9.8"
kotlin = "2.1.0"
coreKtx = "1.15.0"
junit = "4.13.2"
@@ -11,14 +13,13 @@ activity = "1.9.3"
constraintlayout = "2.2.0"
mmkvStatic = "1.3.11"
gson = "2.11.0"
ossLicensesPlugin = "0.10.6"
playServicesOssLicenses = "17.1.0"
quickieFoss = "1.13.1"
rxjava = "3.1.9"
rxandroid = "3.0.2"
rxpermissions = "0.12"
swiperefreshlayout = "1.1.0"
toastcompat = "1.1.0"
editorkit = "2.9.0"
quickieBundled = "1.10.0"
core = "3.5.3"
workRuntimeKtx = "2.10.0"
lifecycleViewmodelKtx = "2.8.7"
@@ -29,6 +30,9 @@ preferenceKtx = "1.2.1"
recyclerview = "1.3.2"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swiperefreshlayout" }
desugar_jdk_libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" }
gradle-license-plugin = { module = "com.jaredsburrows:gradle-license-plugin", version.ref = "gradleLicensePlugin" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
@@ -38,8 +42,7 @@ androidx-activity = { group = "androidx.activity", name = "activity", version.re
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
mmkv-static = { module = "com.tencent:mmkv-static", version.ref = "mmkvStatic" }
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
oss-licenses-plugin = { module = "com.google.android.gms:oss-licenses-plugin", version.ref = "ossLicensesPlugin" }
play-services-oss-licenses = { module = "com.google.android.gms:play-services-oss-licenses", version.ref = "playServicesOssLicenses" }
quickie-foss = { module = "com.github.T8RIN.QuickieExtended:quickie-foss", version.ref = "quickieFoss" }
rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" }
rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" }
rxpermissions = { module = "com.github.tbruyelle:rxpermissions", version.ref = "rxpermissions" }
@@ -47,7 +50,6 @@ toastcompat = { module = "me.drakeet.support:toastcompat", version.ref = "toastc
editorkit = { module = "com.blacksquircle.ui:editorkit", version.ref = "editorkit" }
language-base = { module = "com.blacksquircle.ui:language-base", version.ref = "editorkit" }
language-json = { module = "com.blacksquircle.ui:language-json", version.ref = "editorkit" }
quickie-bundled = { module = "io.github.g00fy2.quickie:quickie-bundled", version.ref = "quickieBundled" }
core = { module = "com.google.zxing:core", version.ref = "core" }
work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" }
work-multiprocess = { module = "androidx.work:work-multiprocess", version.ref = "workRuntimeKtx" }

View File

@@ -16,7 +16,6 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
jcenter()
maven { url = uri("https://jitpack.io") }
}
}

View File

@@ -0,0 +1,27 @@
<p>A V2Ray client for Android, support <a href="https://github.com/XTLS/Xray-core">Xray core</a> and <a href="https://github.com/v2fly/v2ray-core">v2fly core</a></p>
<h3>Telegram Channel</h3>
<p><a href="https://t.me/github_2dust">github_2dust</a></p>
<h3>Usage</h3>
<h4>Geoip and Geosite</h4>
<ul>
<li>geoip.dat and geosite.dat files are in <code>Android/data/com.v2ray.ang/files/assets</code> (path may differ on some Android device)</li>
<li>download feature will get enhanced version in this <a href="https://github.com/Loyalsoldier/v2ray-rules-dat">repo</a> (Note it need a working proxy)</li>
<li>latest official <a href="https://github.com/v2fly/domain-list-community">domain list</a> and <a href="https://github.com/v2fly/geoip">ip list</a> can be imported manually</li>
<li>possible to use third party dat file in the same folder, like <a href="https://guide.v2fly.org/routing/sitedata.html#%E5%A4%96%E7%BD%AE%E7%9A%84%E5%9F%9F%E5%90%8D%E6%96%87%E4%BB%B6">h2y</a></li>
</ul>
<h3>More in our <a href="https://github.com/2dust/v2rayNG/wiki">wiki</a></h3>
<h3>Development guide</h3>
<p>Android project under V2rayNG folder can be compiled directly in Android Studio, or using Gradle wrapper. But the v2ray core inside the aar is (probably) outdated.
The aar can be compiled from the Golang project <a href="https://github.com/2dust/AndroidLibV2rayLite">AndroidLibV2rayLite</a> or <a href="https://github.com/2dust/AndroidLibXrayLite">AndroidLibXrayLite</a>.
For a quick start, read guide for <a href="https://github.com/golang/go/wiki/Mobile">Go Mobile</a> and <a href="https://tutorialedge.net/golang/makefiles-for-go-developers/">Makefiles for Go Developers</a></p>
<p>v2rayNG can run on Android Emulators. For WSA, VPN permission need to be granted via
<code>appops set [package name] ACTIVATE_VPN allow</code></p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1 @@
A V2Ray client for Android, support Xray core and v2fly core

View File

@@ -0,0 +1 @@
v2rayNG

1
hysteria Submodule

Submodule hysteria added at 15e31d48a0

20
libhysteria2.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
targets=(
"aarch64-linux-android21 arm64 arm64-v8a"
"armv7a-linux-androideabi21 arm armeabi-v7a"
"x86_64-linux-android21 amd64 x86_64"
"i686-linux-android21 386 x86"
)
cd "hysteria" || exit
for target in "${targets[@]}"; do
IFS=' ' read -r ndk_target goarch abi <<< "$target"
echo "Building for ${abi} with ${ndk_target} (${goarch})"
CC="${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${ndk_target}-clang" CGO_ENABLED=1 CGO_LDFLAGS="-Wl,-z,max-page-size=16384" GOOS=android GOARCH=$goarch go build -o libs/$abi/libhysteria2.so -trimpath -ldflags "-s -w -buildid=" -buildvcs=false ./app
echo "Built libhysteria2.so for ${abi}"
done