Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 0 additions & 6 deletions .idea/encodings.xml

This file was deleted.

19 changes: 0 additions & 19 deletions .idea/gradle.xml

This file was deleted.

11 changes: 0 additions & 11 deletions .idea/misc.xml

This file was deleted.

5 changes: 0 additions & 5 deletions .idea/scopes/scope_settings.xml

This file was deleted.

8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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 定时器生命周期
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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+ |
Expand Down
1 change: 1 addition & 0 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
7 changes: 2 additions & 5 deletions library/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"
android:maxSdkVersion="28" />

<application
android:label="@string/app_name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public final class Constants {
/**
* SDK 版本号
*/
public static final String VERSION = "8.10.0";
public static final String VERSION = "8.11.0";

/**
* UTF-8 编码
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
public final class ResponseInfo {

/**
* StatusCode >= 100 见:https://developer.qiniu.com/kodo/3928/error-responses
* StatusCode 大于等于 100 见:https://developer.qiniu.com/kodo/3928/error-responses
*/

@Deprecated
Expand Down
127 changes: 97 additions & 30 deletions library/src/main/java/com/qiniu/android/utils/AndroidNetwork.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) {
Expand All @@ -65,22 +66,21 @@ public static boolean isNetWorkReady() {
public static String getHostIP() {
String hostIp = null;
try {
Enumeration nis = NetworkInterface.getNetworkInterfaces();
Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
if (nis == null) {
return null;
}

InetAddress ia = null;
while (nis.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface) nis.nextElement();
NetworkInterface ni = nis.nextElement();
Enumeration<InetAddress> ias = ni.getInetAddresses();
while (ias.hasMoreElements()) {
ia = ias.nextElement();
if (!ia.isLinkLocalAddress() && !ia.isLoopbackAddress()) {
hostIp = ia.getHostAddress();
break;
}
continue;
}
}
} catch (SocketException e) {
Expand All @@ -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;
}
Expand Down Expand Up @@ -166,12 +176,69 @@ 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;

default:
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;
}
}
5 changes: 5 additions & 0 deletions library/src/main/java/com/qiniu/android/utils/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down