干货 | Trip.com Android 11 适配之旅

Andriod之提示java.lang.SecurityException: getDataNetworkTypeForSubscriber导致程序奔溃 修改targetSdkVersion 33 适配Android13后4G网络环境被其它app拉起来提示这个异常。Android11 的权限有关,由于缺少该权限导致无法访问接口而提示安全异常。方法2:我们直接去掉这个函数都可以,直接判断网络是4G(有一定的误差)方法1:我们直接申请READ_PHONE_STATE就行。我们利用XXPermissions框架直接进行申请。我们定位到代码在这行函数。 阅读详情

作者简介

 

Symeon,携程高级移动开发工程师,关注Android前沿技术。

Google Play 商店在 2021 年第 3、4 季度正式加强对应用 targetSdkVersion 的限制,要求应用必须以 API 级别 30 (Android 11) 或更高版本为目标运行环境。

作为第一个强制要求分区存储的 API 级别,Android 11无疑是近几年适配工作较为复杂的版本,各个 APP 的适配进度也被寄予期盼。Trip.com APP 在 2021 年第一季度进行了 Android 11 的适配,本文将从方案设计和技术改造等⻆度,聊一聊我们的实践与感想。


一、背景


1.1 当我们说 “适配” 的时候

假如你在 Android 大版本更新后第一时间升级了仍处在 Beta 阶段的新系统,也许你会发现手机里安装的应用出现了各种奇怪的问题,随着应用更新,闪退等状况才逐渐减少。

从应用的⻆度来看,我们可以把这段时间分为三个阶段,分别是:

  • “应用什么都不做,直接在新系统上使用” → 此时应用可能会闪退

  • “应用针对‘面向所有应用的行为变更’做了对应的更新” → 保证了应用的基本功能可以正常运行,并受到新系统版本的少量限制

  • “应用将 targetSdkVersion 更新至新系统级别” → 能够使用所有新系统特性,并受到新系统版本的完全限制

为了在本篇文章的表述中统一概念、避免翻译和措辞带来误解,下文暂且将这三个阶段称为“未兼容”、“已兼容“、”已适配“。


1.2 Android 11 的特别之处

2019 年的 Google I/O 大会上,Google 演示了 Android 10 的新特性。IMEI(唯一设备标识符)和设备 MAC address(媒体访问控制地址)的访问受到了限制。同时,Android 10 首次正式带来了分区存储 (Scoped storage) 这个期盼已久的功能,但作为一个大型变更,Android 10 的正式版里最后还是留下了一个开关,如果在AndroidManifest.xml文件内设置了android:requestLegacyExternalStorage="true",就相当于关闭了分区存储,仍采用旧版存储模型。 

这相当于留下了一个系统版本的缓冲时间,让各个应用可以逐渐迁移。而当 targetSdkVersion 升级到 Android 11 后,分区存储功能会被强制启用。


二、变更要点


2.1 包可见性

适配 Android 11 之前,APP可以获取到手机已安装的应用列表信息。作为一个国际化的产品,用户隐私是我们非常重要的考量范围,所以这个能力仅在极少数场景下会用到,比如在导航前检查是否有安装地图类APP,或是在点击客服电话时唤起拨号APP。

而在 targetSdkVersion 调整之后,当我们调用 getInstalledPackages() 时,获取到的则是空列表。检查单个 APP是否已经安装也无法正确得知结果。

正因为我们谨慎地使用这个能力,所以适配的工作量也不大,要得知某个 APP 是否安装以及触发某种 Intent 时,就需要在 AndroidManifest.xml 文件内配置对应的 Intent 。例如添加部分导航 APP 的包名、加入拨打电话的 Intent 。参考的配置格式如下:

<manifest package="com.example.game">
    <queries>
        <package android:name="com.example.store" />
        <package android:name="com.example.services" />
        <intent>
            <action android:name="android.intent.action.SEND" />
            <data android:mimeType="image/jpeg" />
        </intent>
</queries>
...
</manifest>

2.2 唯一标识

从 Android 10 开始,Google 限制了对 IMEI 的获取,Android 11 延续了隐私保护的趋势,对其他的有可能作为唯一标识的方法进行了限制,所有不可重置、难以重置的标识符,都会逐步被要求更改为可重置、可变更的标识符。适配 Android 11 后,Mac 地址和 ICCID 的获取都受限了。


2.3 分区存储

在 Android 11 之前的版本,Android 的文件存储可以分成以下几类:

1)内置存储里的应用私有目录

2)外置存储里的应用私有目录

3)外置存储里的媒体文件

4)外置存储里的文件

其中 4 包含了 2 和 3,这里的“包含”指的是,当我们申请了外置存储的读写权限之后,对外置存储内的所有文件都拥有了操作的能力。APP 无需权限就可以读写属于它的应用私有目录,这点在适配 Android 11前后都没有变化。

Android 的存储权限问题一直为人诟病,主要问题在于外置存储里的“媒体”相关权限和“文件”相关权限均被归类在 WRITE_EXTERNAL_STORAGE ,同时“文件”的权限过大,导致应用可以在外置存储里建立文件夹、读取到非本应用的文件,令用户产生不少隐私方面的担忧。

对应到代码里,当我们调用 getExternalStorageDirectory() 时,对应的是外置存储的根目录。

当我们调用 getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) 时,对应的是外置存储的相册目录。

在分区存储开启之后,将受到以下限制:

  • 私有目录访问权限不变

  • 可以直接访问本应用共享的媒体文件

  • 可以申请权限访问其他应用共享的媒体文件

  • 可以在弹窗确认后修改或删除其他应用共享的媒体文件

  • 外置存储的非媒体文件不能直接访问

  • 外置存储的文件可以通过SAF (Storage Access Framework) 访问

简单来说,私有目录不用修改,媒体目录需要适配,非媒体目录不能直接访问。


2.4 其他变更

还有一些变化不大,但也需要适配的变更,下面举两个例子。

自定义 Toast:适配 Android 11 之后,自定义 Toast 受限,限制的思路是将 Toast 承载的信息限制在纯文本。

  • 从后台发送的自定义 Toast 无法弹出

  • Toast 的自定义能力受限,setView() 被标为废弃

  • getView()   方法返回  null  以下方法的返回值并不反映实际值:

    • getHorizontalMargin()

    • getVerticalMargin()

    • getGravity()

    • getXOffset()

    • getYOffset()

  • 以下方法是空操作:

    • setMargin()

    • setGravity()

SP 空安全:适配 Android 11 之后, OnSharedPreferenceChangeListener 增加了 null 的⻛险,每次调用 Editor.clear 时,都会使用 null 键回调 OnSharedPreferenceChangeListener.onSharedPreferenceChanged 。

这便成了一个 NPE ⻛险,需要特别检查。

还有一些变更,如前台服务场景细分与后台权限限制、自动重置授权与单次授权、对非公开接口的限制更新,适配难度不大,在这里就不展开了。


三、适配思路

Trip.com APP 模块数量多,涉及的产线不少,适配工作需要大家协同配合来完成。所以整体的适配思路是,精确定位范围、简化适配工作、提供回退方案。


3.1 精确定位范围

部分业务较多的产线比较少直接操作存储或调用了需适配的 API,因此 Android 11 的适配理论上应该尽可能少地对他们产生影响。对于这样一个协作项目来说,首先就需要确认到底有多少范围需要适配。

对于包可⻅性来说,我们主要检查两个方面的 API 调用,一是获取应用列表,如上文提到的 getInstalledPackages() ,二是检查单个包名是否已安装。除了代码的扫描之外,对于常⻅的使用场景也要做好回归测试工作,例如上文提到过的分享、支付、导航等。

对于唯一标识的变更,我们搜索了 getIccid() 方法的使用,以及检查了标识相关的工具类。对于分区存储,其涉及的函数众多,我们通过以下几类来搜索:

  • 直接获取外置存储的根路径,如 getExternalStorageDirectory

  • 直接获取外置存储的媒体路径,如 getExternalStoragePublicDirectory

  • 直接用字符串拼接的外置存储路径

这里补充一下,在 Android 11 上,虽然文件操作是通过 MediaStore,但是用 File 相关的 API 仍然可以生效,仅是性能效率上有所损失,考虑到从 File 相关 API 变更到MediaStore的复杂度,实际适配过程中根据场景来判断, 并非完全要替换成 MediaStore,因此在搜索范围时,也无需去检查 File 相关 API 的调用。


3.2 简化适配工作

关于包可⻅性的处理,我们统一收口在 AndroidManifest.xml 文件,所有的 Intent 和包名统一管理。分区存储较为复杂,我们提供了一个工具类 IBUStorageEnvironment ,里面实现了和 Environment 相似的函数,以及一些封装好的判断方法,供产线使用。

其中适配的部分细节如下,要适配分区存储,我们需要明确以下几个问题:

  • 什么情况下会启用分区存储?

  • 不同场景如何适配分区存储?

  • 对于媒体文件,是否一定要用 MediaStore ?

我们可以通过 Environment.isExternalStorageLegacy() API 来得知分区存储的启用状态。

1)什么情况下会启用分区存储?

类似于API 29 的 requestLegacyExternalStorage 开关,在API 30 上也有一个停用分区存储的开关 preserveLegacyExternalStorage ,在第一期的适配中,我们将这两个开关都启用,然后将 targetSdkVersion 升级至30,当且仅当使用Android 11的用户新安装 APP 时,才会启用分区存储(包括新用户和卸载重装)。采用这个方案可以减少新旧数据迁移的范围,也能在最大程度上保障现有用户的体验不受影响。对于数据量不大的场景,业务方也可以考虑全部迁移到分区存储。

2)不同场景如何适配分区存储?

举几个例子:

通过 getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) 获取了相册的文件路径,然后读写照片。

推荐的适配方式:满足分区存储条件时,当有性能要求时,使用 MediaStore 来读取媒体文件,无性能要求仍可以通过File来读取。写入场景较少,单独适配。

通过 getExternalStorageDirectory() 获取根目录后,拼接了 "/log.txt" 来建立文件或文件夹。

推荐的适配方式:对于这一类文件,首先推荐都存到私有目录下,如果对“应用卸载后仍要保存”有强烈的需求,可以在开发阶段考虑通过 MediaStore 保存到 Downloads 或者 Documents 文件夹内,正式上线的版本应避免这类操作。

操作了其他应用创建的文件 

推荐的适配方式:做好权限申请的适配,如图片编辑等场景。

3)对于媒体文件,是否一定要用 MediaStore ? 

在 Android 11上,如果操作的是本应用共享的媒体文件,使用原有的 File API也是可以的,但会有性能损耗,所以需要根据具体场景来取舍。


3.3 提供回退方案

迁移的过程中如果严格按照 isExternalStorageLegacy 进行判断,那么通过小版本回退的方式可以重新让应用的 target API 从 30 降低到 29 并重新启用旧逻辑。

不过 targetSdkVersion 的升级伴随着 buildToolsVersion 等更新,而后者升级会带来诸如可空性 (nullable) 等方面的编译期报错,这也是迁移的一部分,如果准备了回退的预案也需要把这部分的改动⻛险考量在内。


四、踩过的坑

在适配工作开始之后,我们也遇到了一些计划之外的波折,这里列举比较典型的几个问题。


4.1 Gradle插件升级适配

适配新系统除了要升级 targetSdkVersion 之外,也需要把 compileSdkVersion 和 buildToolsVersion 一并升级。这里会带来一些编译期的问题,举例来说, ActivityLifecycleCallbacks 的回调里,原本是可空的 activity 参数,适配后变为不可空,而 intent.getStringExtra() 则变成了 @nullable 。这些问题主要来自于 Java 与 Kotlin 混编时,调用的一部分系统 Java 函数在升级后增加了可空性注解,所以在我们的 Kotlin 代码里需要明确做空处理。同时 Lint 也会有少许更新,表现出来的状况是所有模块的开发人员都需要检查各自模块是否在编译和 Lint 环节失败了。

这个部分⻛险较低,因为编译失败或者 Lint 失败的话,会体现在 Merge Request 的 Pipeline 失败,必须修复后才能合并到主分支。考虑上文提到的回退方案时,也需要检查版本回退后新代码是否有不兼容而需要一并 revert 的情况。

除了上述更新之外,因为 Android 11 的包可⻅性用到了 <queries> 标签,而该标签对 AGP (Android Gradle plugin) 的版本有硬性要求。如果直接使用的话,可能会遇到如下问题:

unexpected element <queries> found in <manifest>

此时我们需要升级 AGP 的版本,具体的限制如下:

AGP 的升级同样是需要谨慎评估的,好在 Google 考虑到适配的复杂度,对多个版本都增设了一个小版本,从 AGP 官方的 Release Note 里可以看到小版本升级的变更很少,所以不会引入太多的⻛险因素。但变更很少不代表没有,例如我们也遇到了 xml 解析上面的一些问题,部分模块编译时报如下错误:

Android resource linking failed

这是因为一部分自定义的 attr 没有显式声明其 format,举例如下:

<attr name="inColor" /> //编译失败
<attr name="inColor" format="color" /> //编译成功

4.2 第三方库的内部崩溃及间接API的调用

在测试阶段,我们遇到了如下报错:

java.lang.SecurityException: getDataNetworkTypeForSubscriber: uid xxx does not have
android.permission.READ_PHONE_STATE

以及一个类似的报错:

Caused by: java.lang.SecurityException: getDataNetworkTypeForSubscriber
        at android.os.Parcel.createExceptionOrNull(Parcel.java:2373)
        at android.os.Parcel.createException(Parcel.java:2357)
        at android.os.Parcel.readException(Parcel.java:2340)
        at android.os.Parcel.readException(Parcel.java:2282)
        at
com.android.internal.telephony.ITelephony$Stub$Proxy.getNetworkTypeForSubscriber(ITelep
hony.java:8762)
        at
android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:3031)
        at
android.telephony.TelephonyManager.getNetworkType(TelephonyManager.java:2995)
at ...
at
io.reactivex.internal.operators.completable.CompletableFromRunnable.subscribeActual(Com
pletableFromRunnable.java:35)
        at io.reactivex.Completable.subscribe(Completable.java:2185)
        at
io.reactivex.internal.operators.completable.CompletableSubscribeOn$SubscribeOnObserver.
run(CompletableSubscribeOn.java:64)
        at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
        at
io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
        at
io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThrea
dPoolExecutor.java:301)
        at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

通过堆栈发现一部分问题来自使用的第三方库内部,因为对应的库都比较成熟,升级到对应的兼容版本即可解决。另一部分问题来自类似的内部库,更换 API 并做好异常捕获便解决了。

这里也是一个⻛险点,对于不太方便升级版本(例如使用了某个分支的衍生版本)或是版本跨度太大的第三方库,就会引入额外的复杂度,并且这个问题在最初确定影响范围的时候没有发现,是因为这个API改动属于间接影响到的变更。对于这类问题,我们的处理方式是在适配和测试阶段每发现一个,检查搜索使用了同样API的项目代码, 适配后更新到共享的文档中。

与之类似的还有第三方库内部使用了 BlackList API,也是需要做兼容处理。


4.3 CI/CD 的流程适配

上文也提到了,AGP 等相关升级对Lint等相关检查会产生影响,所以对自动化流程也会产生一些适配的工作,譬如需要确认新的 Lint 规则是否需要列入我们的自定义规则范畴,并且因为更新了新的 SDK 版本,也需要确保对应的机器上已经下载好了相应的依赖,避免在正常的 Pipeline 内触发了下载 SDK 的行为。

除此之外,因为 Android 11引入了分区存储,在 UI 自动化相关的流程里也有不少需要改造的地方,这里举两个比较典型的问题。

  • Android 11的设备无法通过ADB写入外置存储的应用私有目录

  • APP 的文件导出需要一致

具体来说,只要是升级到 Android 11 的设备,ADB便无法直接读写外置存储的应用私有目录了,这属于文章开头定义的“兼容”范畴。这类功能通常用来自定义配置,举个例子,绝大部分 APP 都有测试环境、正式环境的区分,我们在开发阶段可以方便地在不同环境里切换,这里的实现可以有很多种,假如某个 APP 在其私有目录下创建了一个 env.config 文件,在其中写入了环境变量,那么在自动化流程里,通过 ADB 操作该文件,即可实现环境切换的功能。

但升级 Android 11 之后失效了,我们来梳理一下具体是哪些功能受到了影响。

首先,直接读写外置存储的应用私有目录,这代表了应用卸载后配置不会继续留存在测试机里,也就是天然地支持了单个测试单元的配置独立性。其次,应用私有目录对于 APP 来说,是无需存储权限即可访问的,也就意味着这个配置的读取不依赖于运行时的授权,在自动化阶段是非常方便好用的。最后,对于 APP 来说,自动化的侵入性不强,因为配置文件本身通过私有目录存储就是比较常⻅的做法,自动化的动态修改并不需要 APP 做太多的适配。

要解决上述问题,也有很多方案可以选择,例如把自动化标识打进包里、通过运行时参数来传递等等,但都有其局限性,最后我们用了⻛格较为一致、兼容性比较好的方案:首先找到一个 ADB 直接可写、APP 直接可读的目录, 然后把配置文件写入,修改 APP 代码,兼容该目录的读取,最后给自动化流程内增设一个参数重置的环节。

然后就是上面说到的文件导出问题,如上文所说,Android 11开始应用无法在外置存储的根目录直接创建文件夹以读写文件了,所以一些文件的导出操作也需要同步修改,因为自动化流程只在测试流程内使用,并不会影响真实用户,所以相关导出可以直接写入至媒体文件夹,然后通过ADB导出即可。

在相关问题的排查过程中还有一个小插曲,当我们在 Android 11的设备上使用ADB来操作 /mnt/sdcard 时,会遇到如下报错:

adb: error: stat failed when trying to push to /mnt/sdcard/: Permission denied

而当我们用 adb shell 来查看其变化时,会发现它实际上是个符号链接(Symbolic link),在 Android 11设备上, 它显示如下:

$ adb shell ls -al /mnt | grep sdcard
l?????????  ? ?      ?           ?                ? sdcard -> ?

而在Android 11之前的设备上,它显示如下:

$ adb shell ls -al /mnt | grep sdcard
lrwxrwxrwx root     root              2021-02-16 11:17 sdcard -> /sdcard

层层追溯的话可以发现 /mnt/sdcard 可以成功指向 /storage/emulated/0 这个路径。解决方案也很简单,把对 /mnt/sdcard 相关的操作都改为 /sdcard 即可。

这里的有趣之处在于,我们知道 Android 底层仍然是 Linux,所以分区存储等行为变更会在 Linux 的文件系统里有所体现,当我们用相同的办法来查看媒体文件夹时,也能够发现端倪,感兴趣的朋友可以自行探索。

五、总结

系统的升级适配往往涉及面广、⻛险高、收益不明显,我们前后花了一个月的时间,在第一季度结束之际 Trip.com APP 适配了 Android 11,自动化相关的流程也在第二季度初完成了基本适配,上线后稳定运转至今。

回顾这次升级,我们也能从变化上感受到隐私保护愈发增强以及用户体验逐步优化的趋势,篇幅所限,详尽的行为变更和方案细节不再逐一列举。希望本文能够对开发者们有所帮助,在日常工作过程中关切隐私安全、注重用户体验,共建良好发展的 Android 生态。


团队招聘信息

我们是携程国际业务研发团队,致力于国际业务的探索和深耕,在技术上追求极致的用户体验。

如果你向往在一个国际化团队中学习成⻓,期待技术上有突⻜猛进的提升,欢迎加入我们。目前我们客户端/前端/ 后台/数据/测试开发均有开放职位。

简历投递邮箱:tech@trip.com,邮件标题:【姓名】-【携程国际业务】- 【职位】

【推荐阅读】

 “携程技术”公众号

  分享,交流,成长

国家基因组科学数据中心(NGDC)---组学原始数据如何上传GSA 在发表文章之前我们需要将测序的原始数据上传到一个公共库,并在文中提供accession number,实现数据的公开共享,这是国际惯例。以前我们上传数据时只能上传到美国国立生物技术信息中心(NCBI)、欧洲生物信息学研究所(EBI)、日本核酸数据库(DDBJ),现在中国科学院北京基因组研究所(国家生物信息中心)国家基因组科学数据中心 (CNCB-NGDC)—中国的 "NCBI" 已经建立并日渐完善。组学原始数据归档库(GSA)是组学原始数据汇交、存储、管理与共享系统,是国内首个被国际期刊认可的组学数据发布平 阅读详情

相关推荐

用itext读取PDF文件提取对应得字符串

一.maven导入jar包 <!--pdf解析start--> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version...

zhanghua_chinese的博客 3698

SecurityException: getDataNetworkTypeForSubscriber

问题: Error receiving broadcast Intent { act=android.net.conn.CONNECTIVITY_CHANGE flg=0x4200010 (has extras) } in com.superrtc.mediamanager.RTCNetworkReceiver@d1ac701 Caused by: java.lang.SecurityException: getDataNetworkTypeForSubscriber 解决: 将工程targetsdkve

Duker_tec的博客 8152

ADS仿真功率放大器实例学习笔记

ADS仿真功率放大器实例学习笔记

qq_36521926的博客 1万+

adb指令整理

adbremount’的作用相当于‘adbshellmount-orw,remount,rw/system’。注adbremount’将‘/system’部分置于可写入的模式,默认情况下‘/system’部分是只读模式的。ADB,即AndroidDebugBridge是一种允许模拟器或已连接的Android设备进行通信的命令行工具。后台程序在每个模拟器或设备实例上作为后台进程运行。(3)管理设备或手机模拟器上的预定端口。(1)在设备上运行Shell命令;...

weixin_45354197的博客 1647

MATLAB实战:四桥臂逆变器3D-SVPWM调制算法仿真全流程(附代码)

本文提供了一份完整的MATLAB/Simulink实战指南,详细解析了四桥臂逆变器的3D-SVPWM调制算法仿真全流程。文章从工程实践出发,手把手指导如何搭建模型,涵盖从abc静止坐标系变换、三维空间矢量区域判定、作用时间计算到PWM信号生成与调试等核心环节,并附有代码示例和常见问题解决方案,旨在帮助工程师快速掌握这一应对不平衡负载的高效调制技术。

qsc90123456的博客 234

用友T3提示,年度[UFDATA_002_2017]并不存在,导致无法备份迁移。

用友T3提示,年度[UFDATA_002_2017]并不存在,导致无法备份迁移。现在都win11了某个年度账套不存在怎么办?

雨季余静的博客 3562

adb pull和adb push失败问题解决方法

转载自:http://blog.sina.com.cn/s/blog_4b976b2d0100qnwa.html  问题:使用adb pull命令从android系统中读取文件失败。显示:Permission denied 原因:是由于文件权限原因引起。 使用ls -l命令查看android系统中的文件权限为: -rw-rw---- app_51   app_51 也

wulong710的专栏 8818

ABAP CDS Time Functions 全面解析:用 TIMS_IS_VALID 护航时刻字段的正确性

摘要:本文深入解析ABAP CDS时间函数TIMS_IS_VALID的应用,重点介绍其在企业系统时间字段校验中的关键作用。文章指出无效时间数据会导致业务流程混乱,而CDS层校验能有效减少重复逻辑。详细说明TIMS类型格式要求、空值处理规则,并提供两种工程实现方案:在CDS视图中直接派生校验列,或通过ABAP SQL在内存表中批量验证。最后给出可直接运行的代码示例,包括一个ABAP报表演示内存表验证,以及一个CDS View Entity实现系统时间自动映射与校验,帮助开发者在业务场景中快速落地时间校验功能。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 193

Andriod之提示java.lang.SecurityException: getDataNetworkTypeForSubscriber

需要动态申请权限。

sinat_38304525的博客 558

华为OD机考双机位C卷 - 虚拟理财游戏(Java & Python& JS & C/C++ & GO )

华为OD机考双机位C卷 - 虚拟理财游戏(OD上机考试双机位C卷)。提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。

算法大师! 668

【置顶】TEE从入门到精通-[目录]

此专栏讲解包含不限于optee、商用TEE、常规的安全业务设计。但主要基于optee最新代码,深度讲解和剖析各项原理和机制...

baron-周贺贺-代码改变世界ctw 6426

适配 Android 12 遇到的坑

我们升级到Targetsdk29有大半年时间了,今年为了满足审查去除蓝牙的精确定位权限,以及满足上架Google Play的要求,需要将Targetsdkversion升级到31,适配到Android12。这个过程遇到不少坑,这里记录一下,希望能对大家有所帮助。 由于我们在适配Android 29的时候已经适配了Scoped storage,因此这篇文章里面没有这部分的描述。 1 安全组件输出,exported 编译时报错: android:exported needs to

chuyouyinghe的专栏 1万+

【AI产品与商业航图】Flux.1 完全开源 AI 绘图模型:本地部署与 ComfyUI 实战指南

Flux.1是一个开源项目,用户可以自由使用和修改,完全免除使用费用。🖥️本地部署支持:与一些依赖云端计算的工具不同,Flux.1支持本地部署,确保用户可以离线使用并自主控制数据隐私。🔄兼容ComfyUI框架:Flux.1可以无缝集成到ComfyUI中,用户可以享受更加简便和直观的操作界面。🎨卓越的图像生成能力:Flux.1能够生成高质量、细腻的图像,支持多种风格与创作主题的切换。💾低硬件要求。

高校图书馆高级系统架构师/研究馆员,推动高校AI从概念演示到可评审、可交付、可运维:路线图与立项评审、PoC交付、评测回归与上线运维(Baseline/Eval/Ops)。 1737

使用华为scanplus崩溃的问题

scanplus崩溃

a521314963的博客 1209

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

关于在Android 11系统手机上请求READ_PHONE_STATE权限的问题

Android 11系统申请READ_PHONE_STATE权限

后来者的博客 1万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Android SecurityException: getDataNetworkTypeForSubscriber问题修复

前不久,在开发Android视频播放器的时候,使用手机的4G播放时出现了getDataNetworkTypeForSubscriber错误,详细的报错信息如下: Process: com.avatar.buyer.client, PID: 27217 java.lang.SecurityException: getDataNetworkTypeForSubscriber at android.os.Parcel.createExceptionOrNull(Parcel.java:24

xiangzhihong8的专栏 6707

adb push 报错 ...error: failed to copy...

原因:没有权限导致的。

奇点的博客 3502

java.lang.SecurityException解决办法

Exception in thread "main" java.lang.SecurityException: invalid SHA1 signature file digest for com/microsoft/sqlserver/jdbc/SQLServerException.class 插件打成的jar包运行出现这个异常,异常处理办法 1、把源sqljdbc.jar驱动解压到sqlj

shendeguang的专栏 2万+

Android Studio 迁移、使用新项目遇到BUG总结(持续更新)

本篇为总结在迁移别人项目或新项目时候遇到的bug,希望能帮助到大家如有侵权 联系删除部分BUG目录。

林大大的博客 755

android 实用adb push 文件时报错“adb: error: failed to copy”

新手在使用adb push文件时往往会遇到push不进去的情况通过报错信息可以看出,是因为文件夹权限不足导致的,因为是只读文件系统,所以在进行文件复制过程中无法写入文件导致复制失败。

z755924843的专栏 8993

已解决java.lang.SecurityException异常的正确解决方法,亲测有效!!!

SecurityException的发生通常与Java安全管理器(Security Manager)有关。已解决java.lang.SecurityException异常的正确解决方法,亲测有效!!!

小明的Java问道之路 3万+

解决非root机器adb pull报错Permission denied

将文件拉到sdcard再执行adb pull。

。 5738

Android 6.0获取IMEI号是出错,动态获取权限

之前更新了一个版本,获取用户的IMEI设备号,本地手机测试没问题,就放到服务器上,结果有很多用户反应,应用打不开。也不是全部用户,只有少部分Android 6.0系统的用户和一些root过的用户,由于那不到用户手机,只能从错误日志中查看。 出错日志: SUPPORTED_64_BIT_ABIS=[Ljava.lang.String;@cdce4d6 versionCode=42 BOARD

u010880009的博客 2万+

Android 调试错误: java.lang.SecurityException

unity打包Android apk 后,Android调试 出现错误 AndroidJavaException:         java.lang.SecurityException: WifiService: Neither user 10078 nor current process has android.permission.CHANGE_WIFI_MULTICAST_STATE.

梦如风的专栏 9893
上一篇: 干货 | 弱监督学习框架 Snorkel 在大规模文本数据集"自动标注"任务中的实践
下一篇: 干货 | 携程数据血缘构建及应用
携程技术
博客等级 码龄10年 3716粉丝 324原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值