Android 11 中的获取网络类型

Posted

技术标签:

【中文标题】Android 11 中的获取网络类型【英文标题】:GetNetworkType in Android 11 【发布时间】:2020-10-22 20:01:58 【问题描述】:

根据here 发布的更改,getNetworkType 方法已从 android R 及更高版本中弃用。

尝试在 R 编译的应用程序中使用此方法时,会引发以下异常:

java.lang.SecurityException: getDataNetworkTypeForSubscriber: uid 10225 does not have android.permission.READ_PHONE_STATE.
  at android.os.Parcel.createExceptionOrNull(Parcel.java:2285)
  at android.os.Parcel.createException(Parcel.java:2269)
  at android.os.Parcel.readException(Parcel.java:2252)
  at android.os.Parcel.readException(Parcel.java:2194)
  at com.android.internal.telephony.ITelephony$Stub$Proxy.getNetworkTypeForSubscriber(ITelephony.java:7565)
  at android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:2964)
  at android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:2928)
  at com.ironsource.environment.ConnectivityService.getCellularNetworkType(ConnectivityService.java:197)
  at com.ironsource.sdk.service.DeviceData.updateWithConnectionInfo(DeviceData.java:98)
  at com.ironsource.sdk.service.DeviceData.fetchMutableData(DeviceData.java:54)
  at com.ironsource.sdk.service.TokenService.collectDataFromDevice(TokenService.java:120)
  at com.ironsource.sdk.service.TokenService.getRawToken(TokenService.java:177)
  at com.ironsource.sdk.service.TokenService.getToken(TokenService.java:166)
  at com.ironsource.sdk.IronSourceNetwork.getToken(IronSourceNetwork.java:183)

这很好,根据文档可以预期。如果我将应用程序编译到 Android R 之前的任何版本,则不会显示异常。

这个异常表示我需要申请android.permission.READ_PHONE_STATE权限。

我想知道是否有办法使用不需要此权限的任何其他 API 获取网络类型(因为此权限的级别很危险,我宁愿不向用户询问)。

【问题讨论】:

【参考方案1】:

获取 READ_PHONE_STATE 的运行时权限以忽略 getDataNetworkTypeForSubscriber

的崩溃
 @Override
    protected void onStart() 
        super.onStart();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) 

            int res = checkSelfPermission(android.Manifest.permission.READ_PHONE_STATE);
            if (res != PackageManager.PERMISSION_GRANTED) 
                requestPermissions(new String[]android.Manifest.permission.READ_PHONE_STATE, 123);
            

        
    

    private final static int REQUEST_CODE_ASK_PERMISSIONS = 1002;

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions, @NonNull int[] grantResults) 
        switch (requestCode) 
            case REQUEST_CODE_ASK_PERMISSIONS:
                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) 
                    Toast.makeText(getApplicationContext(), "READ_PHONE_STATE Denied", Toast.LENGTH_SHORT)
                            .show();
                 else 
                
                stepAfterSplash();

                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        
    

【讨论】:

【参考方案2】:

您仍然可以使用 getDataNetworkType();此方法不一定需要 READ_PHONE_STATE,如他的文档中所述,但“调用应用程序具有运营商权限”就足够了。

https://developer.android.com/reference/android/telephony/TelephonyManager#getDataNetworkType()

据我所知,获得这些特权可能很棘手/非常困难,您可以考虑获得运营商特权并使用此方法,这也是 getNetworkType() 的建议替代方法。

【讨论】:

我显然已经阅读了这篇文章,但是让应用程序拥有运营商特权并不是一件容易的事(就像你所说的那样)。所以,这真的不是那么有帮助。 ..【参考方案3】:

此方法在您的活动中必然需要 READ_PHONE_STATE,而不仅仅是清单 >>>

// Check if the READ_PHONE_STATE permission is already available.


if(ActivityCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE)
                != PackageManager.PERMISSION_GRANTED) 

            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.READ_PHONE_STATE)) 

                  //here >> use getNetworkType() method
              // like this example
 
              mStationInfo.set_networkType(mTelephonyManager.getNetworkType());
             
           else 

【讨论】:

如果你阅读了我的问题,你会注意到我已经说过我在问是否可以在不使用此权限的情况下实现... 对不起,我没注意到【参考方案4】:

我们可以像这样使用ConnectivityManager#getNetworkCapabilitiesNetworkCapablities#hasTransport

ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkCapabilities caps = cm.getNetworkCapabilities(cm.getActivityNetwork());
boolean isMobile = caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
boolean isWifi = caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);

参考:

android.net.NetworkInfo 此类在 API 级别 29 中已弃用。调用者应改为使用 ConnectivityManager.NetworkCallback API 了解连接变化,或切换到使用 ConnectivityManager#getNetworkCapabilities 或 ConnectivityManager#getLinkProperties 获取信息 同步。请记住,虽然保证回调是 按顺序调用每个事件,同步调用没有这样的 约束,因此不建议使用同步 回调中的方法,因为它们通常不会提供 一致的网络(即:它们可能返回过去或 关于正在处理的事件的未来状态 打回来)。相反,建议调用者只使用 回调,可能记住特定的信息位 他们需要保持从一个回调到另一个回调。

【讨论】:

【参考方案5】:

所以我的朋友,我遇到了和你一样的麻烦,但到目前为止,我使用的是 compileSdkVersion 29 而不是 30 以及 targetSdkVersion 29 和我的 buildToolsVersion 28.0.3 并且我的应用程序加载正常。

p>

由于我的这个问题是由第三方库引起的,所以在修复错误之前我无法单独修复它,但我认为现在这个临时解决方案很好。

【讨论】:

将应用程序编译到 API 29 并不能解决问题... 相关:***.com/questions/67705142/…

以上是关于Android 11 中的获取网络类型的主要内容,如果未能解决你的问题,请参考以下文章

Android获取网络类型--最新最全版

java 手机网络工具类,用于获取android_id,网络类型,以及SIM卡的唯一识别码,运营商

xamarin android,UWP 网络类型和IP地址

截图框架代码原理 android 11

Android 版 Chrome 中的自定义网络通知声音

android打开网页,并保存当前位置源码