Android App-targetSDKVersion28升级为30

这篇具有很好参考价值的文章主要介绍了Android App-targetSDKVersion28升级为30。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

为什么要修改targetSDKVersion?

1、应用开发平台要求(小米)
2、更好的兼容新版本的手机

有targetSDKVersion的位置:

  • App的targetSDKVersion
  • Module中的targetSDKVersion
  • 引入的第三方库中有targetSDKVersion

修改了App和Module中的targetSDKVersion。

存储权限和存储位置问题

修改原因:
Android10(targetSdkVersion29)以后加入了分区存储,针对App设置了外置私有存储空间,卸载App时会被删除,一定程度上解决了卸载App后外置内存仍占用问题。

Android10在获取存储权限上和之前版本有区别。

修改前:

  • targetSDKVersion28
  • 使用EasyPermission框架获取权限。(长时间不更新且不支持新版本Android)
  • 视频、音频、文件存储在外置存储卡【Environment.getExternalStorageDirectory()】中。

修改后:

  • targetSDKVersion30(Android 11)
  • 使用Permission替换EasyPermission获取权限
  • 视频、音频、文件存储存储在私有外置存储中【context.getExternalFilesDir()】。

修改内容:

  • 兼容Android不同版本获取权限。
  • App新版本要处理老版本存储在外置存储卡中的内容。

知识点:
使用创建、读写文件测试对Environment.getExternalStorageDirectory()和context.getExternalFilesDir()目录的使用。

Environment.getExternalStorageDirectory()

  • Android13:同Android11
  • Android11:
    • 动态获取Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE权限后创建读写文件时显示permission denied。
    • 动态获取Manifest.permission.MANAGE_EXTERNAL_STORAGE权限后可以创建并读写文件,获取权限方式是通过Intent intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)跳转至设置页面,用户自行打开允许访问所有文件权限看后才可创建读写文件。
  • Android10:同Android11
  • Android9 动态获取Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE权限后可以创建并读写文件。
  • Android6:动态获取Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE权限后可以创建并读写文件。
  • Android5:不用获取权限可以创建并读写文件。

context.getExternalFilesDir();

  • Android13:不用获取权限可以创建并读写文件。
  • Android11:不用获取权限可以创建并读写文件。
  • Android10:不用获取权限可以创建并读写文件。
  • Android9:不用获取权限可以创建并读写文件。
  • Android6:不用获取权限可以创建并读写文件。
  • Android5:不用获取权限可以创建并读写文件。

修改方案:

  • 修改视频、音频和文件存储位置为外置私有存储空间且不需要获取权限。
  • 为兼容App旧版本存储在外置存储卡中的视频、音频和文件,在读取外置存储卡中的视频、音频和文件时需获取存储权限。

读取相册照片和视频

修改原因:

  • Android10之后读取相册的权限不同且方法也不同。

修改前:

  • 使用RxGalleryFinal框架(长时间不更新且不适配新版本Android)

修改后:

  • 使用PictureSelector框架(适配Android10以后版本-内置有获取权限功能)

保存图片至相册

修改原因:

  • Android10 添加至相册方式和位置不同。

修改后:

  • 兼容不同Android版本

处理方法:

  • Android9及之前版本,将图片保存至外置存储卡,然后通知将其添加到相册数据库,并刷新即可(需存储权限)。
  • Android10及以后版本,不能将图片放置在私有外置存储空间(ContentResolver不支持,会提示错误),将图片放在公共媒体存放位置,然后刷新,使用ContentResolver实现。

实现代码如下:

package com.ypkj.kfpt.http;


import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.widget.Toast;


import androidx.fragment.app.FragmentActivity;


import com.learn.base.permission.PermissionsUtil;
import com.ypkj.kfpt.R;


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.UUID;


/**
 * 下载图片至相册的工具类
 */


public class DonwloadSaveImg {
    private static Context context;
    private static String filePath;
    private static Bitmap mBitmap;
    private static String mSaveMessage = "失败";
    private final static String TAG = "PictureActivity";


    public static void donwloadImg( Context contexts, String filePaths) {
        context = contexts;
        filePath = filePaths;
        PermissionsUtil.getInstance().requestStoragePerm((FragmentActivity) contexts, "", new PermissionsUtil.BaseRequestCallback() {
            @Override
            public void onCallBack() {
                new Thread(saveFileRunnable).start();
            }
        });
    }


    private static Runnable saveFileRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                if (!TextUtils.isEmpty(filePath)) { //网络图片
                    // 对资源链接
                    URL url = new URL(filePath);
                    //打开输入流
                    InputStream inputStream = url.openStream();
                    //对网上资源进行下载转换位图图片
                    mBitmap = BitmapFactory.decodeStream(inputStream);
                    inputStream.close();
                }
                saveBitmap(context, mBitmap);
                mSaveMessage = "图片保存成功!";
            } catch (IOException e) {
                mSaveMessage = "图片保存失败!";
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            messageHandler.sendMessage(messageHandler.obtainMessage());
        }
    };


    private static Handler messageHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {


            Log.d(TAG, mSaveMessage);
            Toast.makeText(context, mSaveMessage, Toast.LENGTH_SHORT).show();
        }
    };




    // 保存bitmap到相册,并兼容AndroidQ
    public static boolean saveBitmap(Context context, Bitmap bitmap) {
        if (bitmap == null) {
            return false;
        }
        boolean isSaveSuccess;
        if (Build.VERSION.SDK_INT < 29) {
            isSaveSuccess = saveImageToGallery(context, bitmap);
        } else {
            isSaveSuccess = saveImageToGalleryQ(context, bitmap);
        }
        return isSaveSuccess;
    }


    /**
     * android 10 以下版本
     */
    private static boolean saveImageToGallery(Context context, Bitmap image) {
        // 首先保存图片
        String storePath = getBitmapFileDir();


        File appDir = new File(storePath);
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        String fileName = UUID.randomUUID().toString() + ".png";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            // 通过io流的方式来压缩保存图片
            boolean isSuccess = image.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();


            // 保存图片后发送广播通知更新数据库
            Uri uri = Uri.fromFile(file);
            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
            if (isSuccess) {
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * android 10 以上版本
     */
    private static boolean saveImageToGalleryQ(Context context, Bitmap image) {
        long mImageTime = System.currentTimeMillis();
        String mImageFileName = UUID.randomUUID().toString() + ".png";
        final ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, getBitmapFileDir());
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName);
        values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
        values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000);
        values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000);
        values.put(MediaStore.MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
        values.put(MediaStore.MediaColumns.IS_PENDING, 1);


        ContentResolver resolver = context.getContentResolver();
        final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        try {
            OutputStream out = resolver.openOutputStream(uri);
            if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
                return false;
            }
            values.clear();
            values.put(MediaStore.MediaColumns.IS_PENDING, 0);
            values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
            resolver.update(uri, values, null, null);
        } catch (Exception e) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                resolver.delete(uri, null);
            }
            return false;
        }
        return true;
    }


    public static String getBitmapFileDir() {
        String BITMAP_FILE_DIRECTORY = context.getString(R.string.appname);
        if (Build.VERSION.SDK_INT < 29) {
            // android 10 以下版本
            return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + BITMAP_FILE_DIRECTORY;
        } else {
            return Environment.DIRECTORY_PICTURES + File.separator + BITMAP_FILE_DIRECTORY;
        }
    }


}

参考文档:文章来源地址https://www.toymoban.com/news/detail-784115.html

  • 一篇文章搞定《Android权限问题(全版本)》https://blog.csdn.net/weixin_45112340/article/details/128905213
  • [ ]应用TargetSdkVersion 30升级适配指南 https://dev.mi.com/distribute/doc/details?pId=1738#_2

到了这里,关于Android App-targetSDKVersion28升级为30的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 升级targetSdkVersion33 解决方法

    因为谷歌上传要求,需要升级targetsdk33下面一些解办法: 使用版本2019.4.20f1 因为31以后sdk缺少dx文件,解决方案是这些文件在文件名称更改为dx.bat. 解决方法如下: 1)进入项目SDK目录下的build-tools33.0.2 目录,比如:C:UsersuserAppDataLocalAndroidSdkbuild-tools33.0.2 2)找到一个名为

    2024年02月09日
    浏览(37)
  • 升级targetSdkVersion至33(以及迁移至Androidx)

    1.设置 android.useAndroidX=true 和 android.enableJetifier=true 2.一键迁移至androidx:Refactor - Migrate to Androidx 3.手动修改未能自动迁移到androidx的部分: android.support.v4.view.ViewPager.PageTransformer - androidx.viewpager.widget.ViewPager.PageTransformer android.support.annotation.NonNull - androidx.annotation.NonNull android.s

    2024年02月07日
    浏览(37)
  • android升级SDK 到30,导致微信登录,支付失败

    当时为了将应用上传 google play ,所以升级了sdk 版本号 targetSdkVersion = 30 ,后来发现升级之后,应用中微信登录,微信支付,都拉不起来了,点击登录,或者支付,没有任何响应。 通过看日志发现, sendReq failed for wechat app signature check failed 是微信没有被拉起, 后来了解资料发现

    2024年02月05日
    浏览(51)
  • android App内下载apk 并升级

    主要代码 1.下载apk代码;安装APP权限申请;3.文件存储; 兼容Android 12 版本 存储权限处理: 1.新建xml文件; 2.manifest配置文件: 注,可运行下载链接 APP内升级代码源码

    2024年02月13日
    浏览(39)
  • Android 系统级APP 升级方案 OTA全流程

    支持原创,请关注专栏: 高质量文章导航 一.Android ota固件编译 OTA 介绍 OTA ( over the air )升级是 Android 系统提供的标准软件升级方式。它功能强大,提供了 完全升级(完整包)、增量升级模式(差异包),可以通过本地升级,也可以通过网络升级 1.完整包 完整包所包含内容

    2024年02月02日
    浏览(86)
  • 【Android】app应用内版本更新升级(DownloadManager下载,适配Android6.0以上所有版本)

    版本的升级和更新是一个线上App所必备的功能,App的升级安装包主要通过 应用商店 或者 应用内下载 两种方式获得,大部分app这两种方式都会具备,应用商店只需要上传对应平台审核通过即可,而应用内更新一般是通过以下几种方式: 1.集成第三方库如 appupdateX、bugly 的更新

    2024年02月11日
    浏览(115)
  • Android实现App内自动升级,适配了安卓7、8及以上版本

            应用发布后,要实现灰度升级控制,如果只依赖各家应用市场是不够的,还需要自己在应用中控制升级逻辑。并且每家应用市场上新审核也是一件很麻烦的事情,尤其像至简网格这样的应用,甚至没在应用市场上架,更不可能依赖它们了。所以必须要在应用中实现自

    2024年02月10日
    浏览(70)
  • Android 13(targetSdkVersion:33)必需添加com.google.android.gms.permission.AD_ID

    关于这个问题个人觉得Google真有点变态。 大概的意思是:你要适配Android 13,必须将targetSdkVersion升至33,这都很正常;你必须添加com.google.android.gms.permission.AD_ID的权限获取,OK,虽然不知道我的APP没有广告为何一定要我加这个,你要加就加呗!!!但变态的是在提交新版本审核

    2024年02月11日
    浏览(48)
  • 面试题打卡30天-day28

    回答一: 在 Git 中, fork 命令是指将其他用户的代码仓库完全复制一份到当前用户自己的账户下,成为一个新的独立代码仓库。与此相对, clone 命令是指在本地将某个远程代码仓库中的代码克隆到本地,成为本地工作区的一个副本。 具体来说, fork 命令会在远程服务端(如

    2024年02月05日
    浏览(45)
  • kubeadm升级k8s版本1.28.2升级至1.28.4(Ubuntu操作系统下)

    1.官网升级说明 升级 kubeadm 集群 | Kubernetes 2. 版本说明 详细参考:版本偏差策略 | Kubernetes Kubernetes 版本以  x.y.z  表示,其中  x  是主要版本,  y  是次要版本, z  是补丁版本。 版本升级控制:         1. 最新版和最老版的 kube-apiserver 实例版本偏差最多为一个次要版本

    2024年02月02日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包