Android targetSDK升级到28,gradle升级4.6遇到的问题

本文详细记录了一次尝试将Android应用的Target SDK从26升级到28的过程,包括解决编译错误、处理HTTP加载限制、应对API黑白灰名单变化等难题。作者分享了解决方案,并探讨了在不同系统版本下的API行为差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  最近看友盟上app使用的设备统计,Android8.1以上的用户超过60%,于是想把targetSDK直接从26改成28,这样就可以更好地适配8.1的用户。但是遇到了如下一些问题,以及最终黑白灰名单的问题无法确认完全搞定,于是放弃掉,还是保留在targetSDK=26,等待新系统Q出来以及P的用户增多稳定后,再一起切换成29吧。

遇到的问题:
1.修改如下android编译参数:

compileSdkVersion = 28
buildToolsVersion = "28.0.3"
targetSdkVersion = 28
supportVersion = "28.0.0"

并修改gradle插件版本成:

classpath 'com.android.tools.build:gradle:3.2.0'

gradle的版本修改成4.6, sync后,编译出现如下错误:
在这里插入图片描述

解决方法: 对着代码看,有一段我是这么写的:

variant.mergedFlavor.versionCode = gitBuildCode()

上面的代码,在Gradle4.6就不支持,不能直接修改,所以不能直接这么用,应该改成这样:

def versionCode = gitBuildCode()

2.Http明文网络加载被限制,报错“Cleartext HTTP traffic to xxx not permitted”,之前可以正常显示的Http图片,以及webview打开报错了。
出异常的系统版本是 O(8.1) P 和 Q, 在 O(8.0)及以下的机型,都可以正常显示。

解决方法: 由于APP里面还有部分接口数据没完全转成https,所以不能用网上一些说的过滤指定域名的方法,需要一个类似通配符,允许所有的http流量,所以是选择了AndroidManifest.xml里的application标签里,加上:

android:usesCleartextTraffic="true"

3.用google工具veridex来静态检测黑白灰名单,但是三个问题:
(1)我明显写入的黑名单方法,工具却没有检测出来,如下图:
在这里插入图片描述
在这里插入图片描述

但是APP运行时候,logcat会报错,提示是黑名单方法:
在这里插入图片描述

(2)veridex工具这段时间也在不断地更新,检测结果已经没有网上文章说的那种dark-grey或者light-grey了,都只是greylist,我不好区分哪些greylist以后是会被禁止使用:
在这里插入图片描述

(3)当targetSDK为不同参数时候,分别运行如下3种测试代码,会有不同的表现:

// 直接在浅灰名单中找的接口
public void testLightGreyList() {
    ReflectUtils.getMethod(TelephonyManager.class, "isMultiSimEnabled");
}

// 直接在深灰名单中找的接口
@TargetApi(Build.VERSION_CODES.M)
public void testDarkGreyList() {
    ReflectUtils.getField(CarrierConfigManager.class, "KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL");
}

// 直接在黑名单中找的接口
public void testBlackList() {
    try {
        ReflectUtils.getMethod(ReflectUtils.getClass("android.net.util.IpUtils"), "ipChecksum", ByteBuffer.class, int.class);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

具体的这三种表现如下表格:

targetSDK系统版本blacklistdark-greylight-grey
28P或Q报错NoSuchFieldException报错NoSuchFieldException正常访问
28低于P报错NoSuchFieldException报错NoSuchFieldException正常访问
低于28P或Q报错NoSuchFieldException正常访问正常访问
低于28低于P报错ClassNotFoundException报错NoSuchFieldException正常访问

鉴于如上第二、第三小点的问题,让我迟疑不决,不知道是否还有其他第三方SDK方法,灰黑名单会变动,导致后面的系统会把他们api禁止掉,希望有人帮忙解答下?

4.不把targetSDK设成28,将其设置成27,也是有一个奇葩的问题如下,虽然有一些比较绕的解决方法,但是感觉实现不优雅。
在这里插入图片描述

综上第三、第四大点的问题,我又讲targetSDK改回26了…

参考:
https://blog.youkuaiyun.com/qq_38900441/article/details/84308348 “Webpage not available err_cleartext_not_permitted”
https://zhuanlan.zhihu.com/p/32190223 “Only fullscreen activities can request orientation?一个搞笑的坑!”

原创文章,欢迎转载,转载请注明:ifish.site

作者:JaydenZhou

<think>嗯,用户的问题是关于在Android Studio项目中动态获取READ_PHONE_STATE权限的。他们的项目用的是Java,compileSdkVersion 28Gradle版本4.6Gradle插件3.2.0。首先,我得回忆一下Android权限机制的变化,特别是运行时权限,也就是从Android 6.0(API 23)开始引入的。 用户提到的compileSdkVersion 28,也就是Android 9,所以运行时权限的处理是必须的。READ_PHONE_STATE属于危险权限,需要动态申请。不过,可能还要注意,在Android 10(API 29)之后,这个权限的访问范围有变化,但用户用的是28,所以可能还不需要处理分区存储的问题,不过这点可能需要确认。 接下来,步骤应该包括:在清单文件中声明权限,检查权限是否已授予,如果没有就请求,处理权限请求的结果。可能用户已经知道要在AndroidManifest.xml里声明,但需要确认是否已经做了。然后,在Activity或Fragment中使用ContextCompat.checkSelfPermission来检查权限状态,使用ActivityCompat.requestPermissions来请求,重写onRequestPermissionsResult来处理结果。 另外,用户可能遇到的情况是,在某些设备上,READ_PHONE_STATE可能涉及到设备标识符,比如IMEI,但Android 10之后对这些信息有更严格的限制。不过由于用户的compileSdkVersion是28,可能不需要处理这些限制,但实际运行时如果设备系统版本较高,可能会有影响。这点可能需要提醒用户,但用户的问题主要是获取权限,而不是获取数据后的处理。 另外,Gradle版本和插件版本是否会影响权限处理?可能不太相关,除非有构建问题,但用户的问题更多是代码层面的。需要确保依赖库的兼容性,但可能不需要特别处理。 还有,用户是否了解如何在Java中实现这些步骤?可能需要给出具体的代码示例,比如如何检查权限,如何发起请求,如何处理回调。比如,使用checkSelfPermission和requestPermissions方法,以及处理onRequestPermissionsResult回调。 另外,要注意READ_PHONE_STATE在Android 10及以上版本中,当应用目标SDK>=29时,即使获得权限,也无法访问非重置的设备标识符。但用户的compileSdkVersion是28,所以目标SDK可能也是28,这时候应该还是可以获取IMEI等信息,但需要确认。如果用户的目标SDK高于28,可能需要调整,但用户的问题可能仅限权限获取,所以这部分可能不需要深入,除非用户提到相关问题。 总结步骤应该是: 1.AndroidManifest.xml中添加权限声明。 2. 检查权限是否已授予。 3. 如果未授予,请求权限。 4. 处理权限请求的结果。 5. 在获得权限后执行相关操作。 可能还需要处理用户拒绝权限的情况,比如显示解释为什么需要这个权限,或者引导用户去设置中启用。但用户的问题可能只需要基本的动态获取流程。 最后,要确保代码示例使用Java,并且适配compileSdkVersion 28的环境。例如,使用ActivityCompat和ContextCompat类的方法。</think>在Android工程中动态获取`READ_PHONE_STATE`权限的步骤如下(针对你的环境配置:Java语言、compileSdkVersion 28Gradle 4.6Gradle插件3.2.0): --- ### **1. 添加权限声明** 在`AndroidManifest.xml`中添加权限声明(**必须步骤,否则请求无效**): ```xml <uses-permission android:name="android.permission.READ_PHONE_STATE" /> ``` --- ### **2. 动态请求权限** 在Activity或Fragment中实现以下逻辑: #### **步骤1:检查权限状态** ```java // 检查是否已获得权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { // 未获得权限,需要请求 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_CODE_READ_PHONE_STATE); // 自定义请求码,如100 } else { // 已获得权限,执行相关操作(如获取IMEI) handlePhoneStatePermissionGranted(); } ``` #### **步骤2:处理权限请求结果** 重写`onRequestPermissionsResult`方法: ```java @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE_READ_PHONE_STATE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限已授予 handlePhoneStatePermissionGranted(); } else { // 权限被拒绝,可提示用户或引导去设置页 Toast.makeText(this, "需要权限才能获取设备信息", Toast.LENGTH_SHORT).show(); } } } ``` --- ### **3. 权限获取后的操作** 实现`handlePhoneStatePermissionGranted()`方法(示例为获取设备IMEI): ```java private void handlePhoneStatePermissionGranted() { TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { String imei = telephonyManager.getImei(); // 需要API 26+ } else { String imei = telephonyManager.getDeviceId(); // 旧版本方式 } } ``` --- ### **注意事项** 1. **兼容性**: - 若应用目标SDK ≥ 29(Android 10+),`READ_PHONE_STATE`权限无法获取IMEI等不可重置标识符,需改用`READ_PRIVILEGED_PHONE_STATE`(仅系统应用可用)或调整业务逻辑。 - 因你的compileSdkVersion为28,目标SDK应≤28,上述代码可直接使用。 2. **拒绝处理**: - 若用户拒绝权限,可通过`shouldShowRequestPermissionRationale()`判断是否需要解释权限用途,并引导用户授权。 3. **设备信息限制**: -Android 10开始,非系统应用无法获取IMEI,需考虑替代方案(如Android ID)。 --- ### **完整代码示例** ```java public class MainActivity extends AppCompatActivity { private static final int REQUEST_CODE_READ_PHONE_STATE = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); requestReadPhoneStatePermission(); } private void requestReadPhoneStatePermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_CODE_READ_PHONE_STATE); } else { handlePhoneStatePermissionGranted(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CODE_READ_PHONE_STATE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { handlePhoneStatePermissionGranted(); } else { Toast.makeText(this, "权限被拒绝,部分功能受限", Toast.LENGTH_SHORT).show(); } } } private void handlePhoneStatePermissionGranted() { TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); String deviceId; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { deviceId = telephonyManager.getImei(); } else { deviceId = telephonyManager.getDeviceId(); } Log.d("DeviceInfo", "Device ID: " + deviceId); } } ``` --- ### **Gradle配置验证** 确保`build.gradle`中`targetSdkVersion` ≤ 28以兼容旧版行为: ```groovy android { compileSdkVersion 28 defaultConfig { targetSdkVersion 28 } } ``` 按此流程即可在Java项目中安全获取`READ_PHONE_STATE`权限。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JaydenZhou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值