Android个版本之间的变更
Android 6.0
运行时权限,可以使用PermissionDispatch框架完成权限控制,也可以自己写代码,不过比较繁琐,如下代码:
@RequiresApi(api = Build.VERSION_CODES.M)
private void initPermission(){
permissionS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
permissionS.add(Manifest.permission.VIBRATE);
permissionS.add(Manifest.permission.CAMERA);
permissionS.add(Manifest.permission.ACCESS_FINE_LOCATION);
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
return;
}
ArrayList<String> needPermission = new ArrayList<>();
for(int i= 0 ; i< permissionS.size(); i++){
if(checkSelfPermission(permissionS.get(i)) != PackageManager.PERMISSION_GRANTED){
needPermission.add(permissionS.get(i));
}
}
if(needPermission.size() > 0){
ActivityCompat.requestPermissions(this, needPermission.toArray(new String[needPermission.size()]), 127);
}
//权限处理结果回调方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 该权限已经通过
} else {
// 权限已经被拒绝
}
return;
}
}
}
Android O 8.0
通知栏notification
每个应用的通知需要为其创建对应的NotificationChannel通知渠道,通知管理器为其创建渠道channel,并且每个应用通知需要设置一个NOTIFICATION_ID
如下代码,写好的兼容代码:
@RequiresApi(api = 26)
private NotificationChannel createNoticationChannel(){
NotificationChannel channel = new NotificationChannel(String.valueOf(NOTIFICATION_ID), "heyichong",
NotificationManager.IMPORTANCE_DEFAULT);
channel.canBypassDnd();//是否绕过请勿打扰模式
channel.enableLights(true);//闪光灯
channel.setLockscreenVisibility(VISIBILITY_SECRET);//锁屏显示通知
channel.setLightColor(Color.RED);//闪关灯的灯光颜色
channel.canShowBadge();//桌面launcher的消息角标
channel.enableVibration(true);//是否允许震动
channel.getAudioAttributes();//获取系统通知响铃声音的配置
channel.getGroup();//获取通知取到组
channel.setBypassDnd(true);//设置可绕过 请勿打扰模式
channel.setVibrationPattern(new long[]{100, 100, 200});//设置震动模式
channel.shouldShowLights();//是否会有灯光
return channel;
}
@Override
public void showNotification() {
Intent cancelIntent = new Intent();
cancelIntent.setAction(DownloadReceiver.INTENT_ACTION_CANCEL);
PendingIntent piCancel = PendingIntent.getBroadcast(this, 0, cancelIntent, 0);
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
mBuilder = new NotificationCompat.Builder(this, String.valueOf(NOTIFICATION_ID));
mNotificationManager.createNotificationChannel(createNoticationChannel());
}else{
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
}
mBuilder.setContentTitle(getString(R.string.start_download))
.setTicker(getString(R.string.start_download)) //通知首次出现在通知栏,带上升动画效果的
.setProgress(100, 0, true)
.setSmallIcon(R.mipmap.ic_launcher)
.addAction(R.drawable.ic_close, getString(R.string.cancel_download), piCancel);
// mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
/**
* 设置为前台service
*/
startForeground(NOTIFICATION_ID, mBuilder.build());
}
添加support-library >= 26
小于26的support库只需要用SDK Manager更新,即可;大于则需要在Android Studio中的根build.gradle添加maven的Google库,如下:
Android 7.0
应用间共享文件
Android 框架强制运行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。假设一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照,或裁切照片。
这时需要用FileProvider来解决该问题:
第一步:在manifest清单文件里注冊provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="包名.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 暂时訪问权限。
第二步:指定共享的文件夹
为了指定共享的文件夹我们须要在资源(res)文件夹下创建一个xml文件夹,然后创建一个名为“file_paths”(名字能够随便起,仅仅要和在manifest注冊的provider所引用的resource保持一致就可以)的资源文件。内容例如以下:
xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="camera_photos" />
</paths>
</resources>
代表的根文件夹: Context.getFilesDir()
代表的根文件夹: Environment.getExternalStorageDirectory()
代表的根文件夹: getCacheDir()
上述代码中path=”“,是有特殊意义的,它代码根文件夹。也就是说你能够向其它的应用共享根文件夹及其子文件夹下不论什么一个文件了,假设你将path设为path=”pictures”,
那么它代表着根文件夹下的pictures文件夹(eg:/storage/emulated/0/pictures),假设你向其它应用分享pictures文件夹范围之外的文件是不行的。
第三步:使用FileProvider
上述准备工作做完之后,如今我们就能够使用FileProvider了。
还是以调用系统相机拍照为例,我们须要将上述拍照代码改动为例如以下:
File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
if (!file.getParentFile().exists())file.getParentFile().mkdirs();
Uri imageUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", file);//通过FileProvider创建一个content类型的Uri
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //加入这一句表示对目标应用暂时授权该Uri所代表的文件
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(intent,1006);
上述代码中主要有两处改变:
1、将之前Uri的scheme类型为file的Uri改成了有FileProvider创建一个content类型的Uri。
2、加入了intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);来对目标应用暂时授权该Uri所代表的文件。
华为Android 9.0
部分华为手机9.0系统在使用Notification或其他组件时,通过startForeground调用时可能会出现奔溃情况,但是其他手机不一定会出现,这个时候就是因为缺少前台服务线程权限,这个不需要运行时获取,在AndroidManifest里面申请即可
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】