├── .gitignore
├── README.md
├── app
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── stub
│ │ ├── BarUtils.java
│ │ └── MainActivity.kt
│ └── res
│ ├── drawable
│ └── common_loading_bg.xml
│ ├── layout
│ └── activity_main.xml
│ ├── values-v21
│ └── styles.xml
│ └── values
│ ├── strings.xml
│ └── styles.xml
├── build.gradle.kts
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle.kts
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea/
5 | .DS_Store
6 | build/
7 | /captures
8 | .externalNativeBuild
9 | .cxx
10 | local.properties
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ClashForAndroid-Geoip
2 |
3 | Geoip from geolite.clash.dev
4 |
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import java.io.*
2 | import java.net.HttpURLConnection
3 | import java.net.URL
4 | import java.util.*
5 |
6 | plugins {
7 | id("com.android.application")
8 | id("kotlin-android")
9 | id("kotlin-android-extensions")
10 | }
11 |
12 | val local = Properties().apply {
13 | FileInputStream(rootProject.file("local.properties"))
14 | .reader(Charsets.UTF_8)
15 | .use(this::load)
16 | }
17 |
18 | fun getGitHeadRefsSuffix(): String {
19 | val url = local.requireProperty("project.geoip_mmdb_version")
20 | val version = (URL(url).openConnection() as HttpURLConnection).apply {
21 | instanceFollowRedirects = true
22 | useCaches = false
23 | requestMethod = "GET"
24 | setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36")
25 | }.inputStream.use { input ->
26 | BufferedReader(InputStreamReader(input)).readText()
27 | }
28 | return version
29 | }
30 |
31 |
32 | android {
33 | compileSdk = 30
34 |
35 | defaultConfig {
36 | applicationId = local.requireProperty("project.package_name")
37 |
38 | minSdk = 21
39 | targetSdk = 30
40 |
41 | versionCode = local.requireProperty("project.version_code").toInt()
42 | versionName = local.requireProperty("project.version_name")
43 |
44 | resValue("string", "package_label", local.requireProperty("project.package_label"))
45 | resValue("string", "geoip_version", getGitHeadRefsSuffix())
46 |
47 | val iconId = if (local.getProperty("project.package_icon_url") != null)
48 | "@mipmap/ic_icon"
49 | else
50 | "@android:drawable/sym_def_app_icon"
51 |
52 | manifestPlaceholders(
53 | mapOf("applicationIcon" to iconId)
54 | )
55 | }
56 |
57 | signingConfigs {
58 | maybeCreate("release").apply {
59 | storeFile(rootProject.file(local.requireProperty("keystore.file")))
60 | storePassword(local.requireProperty("keystore.password"))
61 | keyAlias(local.requireProperty("keystore.key_alias"))
62 | keyPassword(local.requireProperty("keystore.key_password"))
63 | }
64 | }
65 |
66 | buildTypes {
67 | named("release") {
68 | isMinifyEnabled = true
69 | isShrinkResources = true
70 | proguardFiles(
71 | getDefaultProguardFile("proguard-android-optimize.txt"),
72 | "proguard-rules.pro"
73 | )
74 | signingConfig = signingConfigs["release"]
75 | }
76 | }
77 |
78 | sourceSets {
79 | named("main") {
80 | assets {
81 | srcDir(buildDir.resolve("mmdb"))
82 | }
83 | res {
84 | srcDir(buildDir.resolve("icon"))
85 | }
86 | }
87 | }
88 |
89 | applicationVariants.all {
90 | val variant = this
91 | variant.outputs
92 | .map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl }
93 | .forEach { output ->
94 | output.outputFileName = output.outputFileName
95 | .replace("app-", "geoip.clash.dev-")
96 | .replace(".apk", "-${getGitHeadRefsSuffix().trim()}(${variant.versionCode}).apk")
97 | }
98 | }
99 | }
100 |
101 |
102 |
103 | task("fetchMMDB") {
104 | val url = local.requireProperty("project.geoip_mmdb_url")
105 | val outputDir = buildDir.resolve("mmdb").apply { mkdirs() }
106 |
107 | doLast {
108 | //URL(url).openStream()
109 | (URL(url).openConnection() as HttpURLConnection).apply {
110 | instanceFollowRedirects = true
111 | useCaches = false
112 | requestMethod = "GET"
113 | setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36")
114 | }.inputStream.use { input ->
115 | FileOutputStream(outputDir.resolve("Country.mmdb")).use { output ->
116 | input.copyTo(output)
117 | }
118 | }
119 | }
120 | }
121 |
122 | task("fetchIcon") {
123 | val url = local.getProperty("project.package_icon_url")
124 |
125 | if (url != null) {
126 | val outputDir = buildDir.resolve("icon/mipmap").apply { mkdirs() }
127 |
128 | require(url.endsWith(".png")) {
129 | throw IllegalArgumentException("icon must be .png file")
130 | }
131 |
132 | doLast {
133 | URL(url).openStream().use { input ->
134 | FileOutputStream(outputDir.resolve("ic_icon.png")).use { output ->
135 | input.copyTo(output)
136 | }
137 | }
138 | }
139 | }
140 | }
141 |
142 | afterEvaluate {
143 | android.applicationVariants.forEach {
144 | it.mergeResourcesProvider.get().dependsOn(tasks["fetchIcon"])
145 | it.mergeAssetsProvider.get().dependsOn(tasks["fetchMMDB"])
146 | }
147 | }
148 |
149 |
150 | dependencies {
151 | implementation("androidx.appcompat:appcompat:1.2.0")
152 | implementation("org.jetbrains.kotlin:kotlin-stdlib:${rootProject.extra["kotlin_version"]}")
153 | implementation("androidx.constraintlayout:constraintlayout:2.0.4")
154 | }
155 |
156 | fun Properties.requireProperty(key: String): String {
157 | return getProperty(key)
158 | ?: throw GradleScriptException(
159 | "property \"$key\" not found in local.properties",
160 | FileNotFoundException()
161 | )
162 | }
163 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | -dontobfuscate
24 |
25 | -keep class stub.R
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
33 | * author: Blankj 34 | * blog : http://blankj.com 35 | * time : 2016/09/23 36 | * desc : utils about bar 37 | *38 | */ 39 | public final class BarUtils { 40 | 41 | /////////////////////////////////////////////////////////////////////////// 42 | // status bar 43 | /////////////////////////////////////////////////////////////////////////// 44 | 45 | private static final String TAG_STATUS_BAR = "TAG_STATUS_BAR"; 46 | private static final String TAG_OFFSET = "TAG_OFFSET"; 47 | private static final int KEY_OFFSET = -123; 48 | 49 | private BarUtils() { 50 | throw new UnsupportedOperationException("u can't instantiate me..."); 51 | } 52 | 53 | 54 | /** 55 | * Set the navigation bar's visibility. 56 | * 57 | * @param window The window. 58 | * @param isVisible True to set navigation bar visible, false otherwise. 59 | */ 60 | public static void setNavBarVisibility(@NonNull Context context, @NonNull final Window window, boolean isVisible) { 61 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; 62 | final ViewGroup decorView = (ViewGroup) window.getDecorView(); 63 | for (int i = 0, count = decorView.getChildCount(); i < count; i++) { 64 | final View child = decorView.getChildAt(i); 65 | final int id = child.getId(); 66 | if (id != View.NO_ID) { 67 | String resourceEntryName = getResNameById(context, id); 68 | if ("navigationBarBackground".equals(resourceEntryName)) { 69 | child.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE); 70 | } 71 | } 72 | } 73 | final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 74 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 75 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 76 | if (isVisible) { 77 | decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() & ~uiOptions); 78 | } else { 79 | decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | uiOptions); 80 | } 81 | } 82 | 83 | 84 | private static String getResNameById(Context context, int id) { 85 | try { 86 | return context.getResources().getResourceEntryName(id); 87 | } catch (Exception ignore) { 88 | return ""; 89 | } 90 | } 91 | 92 | /** 93 | * Set the navigation bar's color. 94 | * 95 | * @param activity The activity. 96 | * @param color The navigation bar's color. 97 | */ 98 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 99 | public static void setNavBarColor(@NonNull final Activity activity, @ColorInt final int color) { 100 | setNavBarColor(activity.getWindow(), color); 101 | } 102 | 103 | /** 104 | * Set the navigation bar's color. 105 | * 106 | * @param window The window. 107 | * @param color The navigation bar's color. 108 | */ 109 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 110 | public static void setNavBarColor(@NonNull final Window window, @ColorInt final int color) { 111 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 112 | window.setNavigationBarColor(color); 113 | } 114 | 115 | /** 116 | * Return the color of navigation bar. 117 | * 118 | * @param activity The activity. 119 | * @return the color of navigation bar 120 | */ 121 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 122 | public static int getNavBarColor(@NonNull final Activity activity) { 123 | return getNavBarColor(activity.getWindow()); 124 | } 125 | 126 | /** 127 | * Return the color of navigation bar. 128 | * 129 | * @param window The window. 130 | * @return the color of navigation bar 131 | */ 132 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 133 | public static int getNavBarColor(@NonNull final Window window) { 134 | return window.getNavigationBarColor(); 135 | } 136 | 137 | 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/java/stub/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package stub 2 | 3 | import android.os.Bundle 4 | import android.os.Handler 5 | import android.os.Looper 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.appcompat.app.AppCompatActivity 9 | import kotlinx.android.synthetic.main.activity_main.* 10 | 11 | class MainActivity : AppCompatActivity() { 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | BarUtils.setNavBarVisibility(this, window, false) 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_main) 16 | 17 | layout.setOnClickListener { 18 | finish() 19 | } 20 | 21 | msgTv.text = "${getString(R.string.package_label)} \nversion ${getString(R.string.geoip_version)}" 22 | Handler(Looper.getMainLooper()).postDelayed({ 23 | finish() 24 | }, 4000L) 25 | } 26 | 27 | override fun overridePendingTransition(enterAnim: Int, exitAnim: Int) { 28 | super.overridePendingTransition(0, 0) 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_loading_bg.xml: -------------------------------------------------------------------------------- 1 | 2 |