diff --git a/.gitignore b/.gitignore
index cf98a9627..18e3b47d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,5 +40,10 @@ java_pid*
library/library.iml
.idea/*
-# Claude Code
-.claude/
+# AI tool settings
+.claude/settings.local.json
+!.claude/skills
+!.trae/skills
+!.trae/rules
+!.kiro/skills
+!.kiro/steering
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 97626ba45..000000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index b188df6b4..000000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 4e9665c8d..000000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml
deleted file mode 100644
index 922003b84..000000000
--- a/.idea/scopes/scope_settings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index df1fbe521..022807e33 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,12 @@
#Changelog
+## 8.11.0(2026-04-14)
+* 调整
+ * 重构网络类型判断逻辑,API 29+ 使用 NetworkCapabilities,API 1-28 使用 TelephonyManager 细分蜂窝代际
+ * 优化权限声明,移除 ACCESS_WIFI_STATE、READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE,READ_PHONE_STATE 限制 maxSdkVersion 为 28
+ * 增加 NETWORK_CLASS_MOBILE 常量,无法细分蜂窝代际时统一返回 mobile
+ * 增加 5G 网络类型识别
+ * isNetWorkReady() 方法适配 NetworkCapabilities
+
## 8.10.0(2026-03-17)
* 调整
* 解耦 TransactionManager 定时器生命周期
diff --git a/README.md b/README.md
index cabff33d9..5a200dff0 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ https://github.com/qiniudemo/qiniu-lab-android
| Qiniu SDK 版本 | 最低 Android版本 | 依赖库版本 |
|--------------|-----------------|------------------------|
+| 8.11.x | Android 4.0+ | okhttp 4+ |
| 8.10.x | Android 4.0+ | okhttp 4+ |
| 8.9.x | Android 4.0+ | okhttp 4+ |
| 8.8.x | Android 4.0+ | okhttp 4+ |
diff --git a/library/build.gradle b/library/build.gradle
index 807123bd1..ff3629239 100755
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -64,6 +64,7 @@ dependencies {
// implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation 'org.conscrypt:conscrypt-android:2.5.3'
implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation 'androidx.annotation:annotation:1.9.1'
androidTestImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml
index 3b7e472b2..a9abf90ce 100644
--- a/library/src/main/AndroidManifest.xml
+++ b/library/src/main/AndroidManifest.xml
@@ -2,12 +2,9 @@
xmlns:tools="http://schemas.android.com/tools">
-
-
-
-
+
= 100 见:https://developer.qiniu.com/kodo/3928/error-responses
+ * StatusCode 大于等于 100 见:https://developer.qiniu.com/kodo/3928/error-responses
*/
@Deprecated
diff --git a/library/src/main/java/com/qiniu/android/utils/AndroidNetwork.java b/library/src/main/java/com/qiniu/android/utils/AndroidNetwork.java
index a46ed3df5..6a54c98e1 100644
--- a/library/src/main/java/com/qiniu/android/utils/AndroidNetwork.java
+++ b/library/src/main/java/com/qiniu/android/utils/AndroidNetwork.java
@@ -5,25 +5,18 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Process;
-import android.telephony.CellInfo;
-import android.telephony.CellInfoCdma;
-import android.telephony.CellInfoGsm;
-import android.telephony.CellInfoLte;
-import android.telephony.CellInfoWcdma;
-import android.telephony.CellSignalStrengthCdma;
-import android.telephony.CellSignalStrengthGsm;
-import android.telephony.CellSignalStrengthLte;
-import android.telephony.CellSignalStrengthWcdma;
import android.telephony.TelephonyManager;
+import androidx.annotation.RequiresApi;
+
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
-import java.util.List;
/**
* Created by bailong on 16/9/7.
@@ -47,7 +40,15 @@ public static boolean isNetWorkReady() {
}
ConnectivityManager connMgr = (ConnectivityManager)
c.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (connMgr == null) {
+ return true;
+ }
try {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ NetworkCapabilities caps = connMgr.getNetworkCapabilities(connMgr.getActiveNetwork());
+ return caps != null && caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ }
+
NetworkInfo info = connMgr.getActiveNetworkInfo();
return info != null && info.isConnected();
} catch (Exception e) {
@@ -65,14 +66,14 @@ public static boolean isNetWorkReady() {
public static String getHostIP() {
String hostIp = null;
try {
- Enumeration nis = NetworkInterface.getNetworkInterfaces();
+ Enumeration nis = NetworkInterface.getNetworkInterfaces();
if (nis == null) {
return null;
}
InetAddress ia = null;
while (nis.hasMoreElements()) {
- NetworkInterface ni = (NetworkInterface) nis.nextElement();
+ NetworkInterface ni = nis.nextElement();
Enumeration ias = ni.getInetAddresses();
while (ias.hasMoreElements()) {
ia = ias.nextElement();
@@ -80,7 +81,6 @@ public static String getHostIP() {
hostIp = ia.getHostAddress();
break;
}
- continue;
}
}
} catch (SocketException e) {
@@ -96,45 +96,55 @@ public static String getHostIP() {
* {@link Constants#NETWORK_CLASS_2_G}
* {@link Constants#NETWORK_CLASS_3_G}
* {@link Constants#NETWORK_CLASS_4_G}
- * ...
+ * {@link Constants#NETWORK_CLASS_5_G}
+ * {@link Constants#NETWORK_CLASS_MOBILE}
*
* @param context context
* @return 网络类型
*/
public static String networkType(Context context) {
try {
- return networkTypeWithException(context);
+ return getNetWorkClass(context);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
- private static String networkTypeWithException(Context context) throws Exception {
+ private static String getNetWorkClass(Context context) {
if (context == null) {
return Constants.NETWORK_CLASS_UNKNOWN;
}
- ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (connectivity == null) {
- return Constants.NETWORK_CLASS_UNKNOWN;
+ // API 29+ getNetworkType() 已废弃,直接用 NetworkCapabilities
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ return getNetworkClassByConnectivity(context);
}
- NetworkInfo networkInfo = connectivity.getActiveNetworkInfo();
- if (networkInfo == null || !networkInfo.isConnected()) {
- return Constants.NETWORK_CLASS_UNKNOWN;
+ // API 1-28 优先用 TelephonyManager,结果为 unknown 时降级
+ String networkType = getNetworkTypeByTelephony(context);
+ if (networkType != null && !Constants.NETWORK_CLASS_UNKNOWN.equals(networkType)) {
+ return networkType;
}
- int netWorkType = networkInfo.getType();
- if (netWorkType == ConnectivityManager.TYPE_WIFI) {
- return Constants.NETWORK_WIFI;
- } else if (netWorkType == ConnectivityManager.TYPE_MOBILE) {
- return getNetWorkClass(context);
+ // API 23+ 使用 NetworkCapabilities(无需 READ_PHONE_STATE 权限)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return getNetworkClassByConnectivity(context);
}
- return Constants.NETWORK_CLASS_UNKNOWN;
+
+ // API < 23 使用旧版 ConnectivityManager 判断 WiFi / 移动网络
+ return getNetworkClassByLegacyConnectivity(context);
}
- private static String getNetWorkClass(Context context) {
+ /**
+ * 通过 TelephonyManager 获取网络类型(2G/3G/4G/5G)
+ * API < 23 时无需权限,API 23-28 需要 READ_PHONE_STATE 权限
+ *
+ * @param context context
+ * @return 网络类型
+ */
+ @SuppressLint("MissingPermission")
+ private static String getNetworkTypeByTelephony(Context context) {
if (context.checkPermission(Manifest.permission.READ_PHONE_STATE, Process.myPid(), Process.myUid()) != PackageManager.PERMISSION_GRANTED) {
return Constants.NETWORK_CLASS_UNKNOWN;
}
@@ -166,7 +176,6 @@ private static String getNetWorkClass(Context context) {
case TelephonyManager.NETWORK_TYPE_LTE:
return Constants.NETWORK_CLASS_4_G;
-
case TelephonyManager.NETWORK_TYPE_NR:
return Constants.NETWORK_CLASS_5_G;
@@ -174,4 +183,62 @@ private static String getNetWorkClass(Context context) {
return Constants.NETWORK_CLASS_UNKNOWN;
}
}
+
+ /**
+ * 使用旧版 ConnectivityManager 获取网络类型
+ * 适用于 API < 23(NetworkCapabilities 不可用)的场景
+ *./
+ * @param context context
+ * @return 网络类型
+ */
+ @SuppressWarnings("deprecation")
+ private static String getNetworkClassByLegacyConnectivity(Context context) {
+ ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (cm == null) {
+ return Constants.NETWORK_CLASS_UNKNOWN;
+ }
+
+ NetworkInfo info = cm.getActiveNetworkInfo();
+ if (info == null || !info.isConnected()) {
+ return Constants.NETWORK_CLASS_UNKNOWN;
+ }
+
+ switch (info.getType()) {
+ case ConnectivityManager.TYPE_WIFI:
+ return Constants.NETWORK_WIFI;
+ case ConnectivityManager.TYPE_MOBILE:
+ return Constants.NETWORK_CLASS_MOBILE;
+ default:
+ return Constants.NETWORK_CLASS_UNKNOWN;
+ }
+ }
+
+ /**
+ * 使用 NetworkCapabilities 获取网络类型(无需 READ_PHONE_STATE 权限)
+ * API 23+
+ *
+ * @param context context
+ * @return 网络类型
+ */
+ @RequiresApi(Build.VERSION_CODES.M)
+ private static String getNetworkClassByConnectivity(Context context) {
+ ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (cm == null) {
+ return Constants.NETWORK_CLASS_UNKNOWN;
+ }
+
+ NetworkCapabilities caps = cm.getNetworkCapabilities(cm.getActiveNetwork());
+ if (caps == null) {
+ return Constants.NETWORK_CLASS_UNKNOWN;
+ }
+
+ if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ return Constants.NETWORK_WIFI;
+ }
+ if (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ // 无法细分 2G/3G/4G/5G,统一返回 mobile
+ return Constants.NETWORK_CLASS_MOBILE;
+ }
+ return Constants.NETWORK_CLASS_UNKNOWN;
+ }
}
diff --git a/library/src/main/java/com/qiniu/android/utils/Constants.java b/library/src/main/java/com/qiniu/android/utils/Constants.java
index 40468b2bc..ebd109e80 100644
--- a/library/src/main/java/com/qiniu/android/utils/Constants.java
+++ b/library/src/main/java/com/qiniu/android/utils/Constants.java
@@ -15,6 +15,11 @@ public class Constants {
*/
public static final String NETWORK_WIFI = "wifi";
+ /**
+ * mobile network (2G/3G/4G/5G, without precise classification)
+ */
+ public static final String NETWORK_CLASS_MOBILE = "mobile";
+
/**
* "2G" networks
*/