• Android7.0发布已经有一个多月了,Android7.0在给用户带来一些新的特性的同时,也给开发者带来了新的挑战,这几天我将应用适配到Android7.0,其中也遇到了不少问题也踩了一些坑,在这里就把我在Android7.0适配上的...

    Android7.0(Android N)适配教程,心得

    Android7.0发布已经有一个多月了,Android7.0在给用户带来一些新的特性的同时,也给开发者带来了新的挑战,这几天我将应用适配到Android7.0,其中也遇到了不少问题也踩了一些坑,在这里就把我在Android7.0适配上的一些心得分享给大家,让大家的应用能早一天跑在Android7.0上。

    权限更改

    随着Android版本越来越高,Android对隐私的保护力度也越来越大。从Android6.0引入的动态权限控制(Runtime Permissions)到Android7.0的“私有目录被限制访问”,“StrictMode API 政策”。这些更改在为用户带来更加安全的操作系统的同时也为开发者带来了一些新的任务。如何让你的APP能够适应这些改变而不是cash,是摆在每一位Android开发者身上的责任。

    目录被限制访问

    一直以来,在目录及文件的访问保护方面iOS做的是很到位的,如:iOS的沙箱机制。但,Android在这方面的保护就有些偏弱了,在Android中应用可以读写手机存储中任何一个目录及文件,这也带来了很多的安全问题。现在Android也在着力解决这一问题。

    在Android7.0中为了提高私有文件的安全性,面向 Android N 或更高版本的应用私有目录将被限制访问。对于这个权限的更改开发者需要留意一下改变:

    应对策略:这项权限的变更将意味着你无法通过File API访问手机存储上的数据了,基于File API的一些文件浏览器等也将受到很大的影响,看到这大家是不是惊呆了呢,不过迄今为止,这种限制尚不能完全执行。 应用仍可能使用原生 API 或 File API 来修改它们的私有目录权限。 但是,Android官方强烈反对放宽私有目录的权限。可以看出收起对私有文件的访问权限是Android将来发展的趋势。

    • 给其他应用传递 file:// URI 类型的Uri,可能会导致接受者无法访问该路径。 因此,在Android7.0中尝试传递 file:// URI 会触发 FileUriExposedException。

    应对策略:大家可以通过使用FileProvider来解决这一问题。

    应对策略:大家可以通过ContentResolver.openFileDescriptor()来访问由 DownloadManager 公开的文件。

    应用间共享文件

    在Android7.0系统上,Android 框架强制执行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照,或裁切照片

    应对策略:若要在应用间共享文件,可以发送 content:// URI类型的Uri,并授予 URI 临时访问权限。 进行此授权的最简单方式是使用 FileProvider类。 如需有关权限和共享文件的更多信息,请参阅共享文件。

    在Android7.0上调用系统相机拍照,裁切照片

    调用系统相机拍照

    在Android7.0之前,如果你想调用系统相机拍照可以通过以下代码来进行:

    File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
    if (!file.getParentFile().exists())file.getParentFile().mkdirs();
    Uri imageUri = Uri.fromFile(file);
    Intent intent = new Intent();
    intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
    startActivityForResult(intent,1006);

    Android7.0拍照.png

    在Android7.0上使用上述方式调用系统相拍照会抛出如下异常:

    android.os.FileUriExposedException: file:////storage/emulated/0/temp/1474956193735.jpg exposed beyond app through Intent.getData()
    at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
    at android.net.Uri.checkFileUriExposed(Uri.java:2346)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8933)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8894)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)
    at android.app.Activity.startActivityForResult(Activity.java:4223)
    ...
    at android.app.Activity.startActivityForResult(Activity.java:4182)

    Android7.0拍照闪退.png

    这是由于Android7.0执行了“StrictMode API 政策禁”的原因,不过小伙伴们不用担心,上文讲到了可以用FileProvider来解决这一问题,
    现在我们就来一步一步的解决这个问题。

    使用FileProvider

    使用FileProvider的大致步骤如下:
    第一步:在manifest清单文件中注册provider

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.jph.takephoto.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所代表的文件。

    心得:上述代码通过FileProviderUri getUriForFile (Context context, String authority, File file)
    静态方法来获取Uri,该方法中authority参数就是清单文件中注册provider的android:authorities="com.jph.takephoto.fileprovider"
    对Web服务器如tomcat,IIS比较熟悉的小伙伴,都只知道为了网站内容的安全和高效,Web服务器都支持为网站内容设置一个虚拟目录,其实FileProvider也有异曲同工之处。

    getUriForFile方法获取的Uri打印出来如下:

    content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg`。  

    其中camera_photos就是file_paths.xml中paths的name。

    因为上述指定的path为path="",所以content://com.jph.takephoto.fileprovider/camera_photos/代表的真实路径就是根目录,即:/storage/emulated/0/
    content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg代表的真实路径是:/storage/emulated/0/temp/1474960080319.jpg

    另外,推荐大家使用开源工具库TakePhoto
    TakePhoto是一款在Android设备上获取照片(拍照或从相册、文件中选择)、裁剪图片、压缩图片的开源工具库。

    裁切照片

    在Android7.0之前,你可以通过如下方法来裁切照片:

    File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
    if (!file.getParentFile().exists())file.getParentFile().mkdirs();
    Uri outputUri = Uri.fromFile(file);
    Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg"));
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(imageUri, "image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", 1);
    intent.putExtra("aspectY", 1);
    intent.putExtra("scale", true);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    intent.putExtra("noFaceDetection", true); // no face detection
    startActivityForResult(intent,1008);

    和拍照一样,上述代码在Android7.0上同样会引起android.os.FileUriExposedException异常,解决办法就是上文说说的使用FileProvider

    然后,将上述代码改为如下即可:

    File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
    if (!file.getParentFile().exists())file.getParentFile().mkdirs();
    Uri outputUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider",file);
    Uri imageUri=FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//通过FileProvider创建一个content类型的Uri
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.setDataAndType(imageUri, "image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", 1);
    intent.putExtra("aspectY", 1);
    intent.putExtra("scale", true);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    intent.putExtra("noFaceDetection", true); // no face detection
    startActivityForResult(intent,1008);

    另外,裁切照片推荐大家使用开源工具库TakePhoto
    TakePhoto是一款在Android设备上获取照片(拍照或从相册、文件中选择)、裁剪图片、压缩图片的开源工具库。

    电池和内存

    Android 6.0(API 级别 23)引入了低电耗模式,Android7.0在电池和内存上又做了进一步优化,
    来减少Android应用对电量的消耗以及对内存的占用。这些优化所带来的一些规则的变更可能会影响你的应用访问系统资源,以及你的系统通过特定隐式 Intent 与其他应用互动的方式。
    所以开发人员需要特别注意这些改变。

    低电耗模式

    在低电耗模式下,当用户设备未插接电源、处于静止状态且屏幕关闭时,该模式会推迟 CPU 和网络活动,从而延长电池寿命。
    Android7.0通过在设备未插接电源且屏幕关闭状态下、但不一定要处于静止状态(例如用户外出时把手持式设备装在口袋里)时应用部分 CPU 和网络限制,进一步增强了低电耗模式。

    也就是说,Android7.0会在手机屏幕关闭的状态下,限时应用对CPU以及网络的使用。

    具体规则如下:

    1. 当设备处于充电状态且屏幕已关闭一定时间后,设备会进入低电耗模式并应用第一部分限制: 关闭应用网络访问、推迟作业和同步。
    2. 如果进入低电耗模式后设备处于静止状态达到一定时间,系统则会对 PowerManager.WakeLockAlarmManager
      闹铃、GPS 和 Wi-Fi 扫描应用余下的低电耗模式限制。 无论是应用部分还是全部低电耗模式限制,系统都会唤醒设备以提供简短的维护时间窗口,在此窗口期间,应用程序可以访问网络并执行任何被推迟的作业/同步。

    后台优化

    小伙伴们都知道在Android中有一些隐式广播,使用这些隐式广播可以做一些特定的功能,如,当手机网络变成WiFi时自动下载更新包等。
    但,这些隐式广播会在后台频繁启动已注册侦听这些广播的应用,从而带来很大的电量消耗,为缓解这一问题来提升设备性能和用户体验,在Android 7.0中删除了三项隐式广播,以帮助优化内存使用和电量消耗。

    Android 7.0 应用了以下优化措施:

    • 在 Android 7.0上 应用不会收到 CONNECTIVITY_ACTION 广播,即使你在manifest清单文件中设置了请求接受这些事件的通知。 但,在前台运行的应用如果使用BroadcastReceiver 请求接收通知,则仍可以在主线程中侦听 CONNECTIVITY_CHANGE。
    • 在 Android 7.0上应用无法发送或接收 ACTION_NEW_PICTUREACTION_NEW_VIDEO 类型的广播。

    应对策略:Android 框架提供多个解决方案来缓解对这些隐式广播的需求。 例如,JobScheduler API
    提供了一个稳健可靠的机制来安排满足指定条件(例如连入无限流量网络)时所执行的网络操作。 您甚至可以使用 JobScheduler API 来适应内容提供程序变化。

    另外,大家如果想了解更多关于后台的优化可查阅后台优化

    移动设备会经历频繁的连接变更,例如在 Wi-Fi 和移动数据之间切换时。 目前,可以通过在应用清单中注册一个接收器来侦听隐式 CONNECTIVITY_ACTION 广播,
    让应用能够监控这些变更。 由于很多应用会注册接收此广播,因此单次网络切换即会导致所有应用被唤醒并同时处理此广播。

    以上是,我在Android7.0上适配上的一些心得,小伙伴们如果有遇到问题可以在下方留言。

    最后

    既然来了,留下个喜欢再走吧,鼓励我继续创作(^_^)∠※

    如果喜欢我的文章,那就关注我的博客吧,让我们一起做朋友~~

    戳这里,加关注哦:

    微博:第一时间获取推送
    个人博客:干货文章都在这里哦
    GitHub:我的开源项目

    展开全文
  • Android7.0 适配心得

    2016-09-29 16:12:05
    Android7.0发布已经有一个多月了,Android7.0在给用户带来一些新的特性的同时,也给开发者带来了新的挑战,这几天我将应用适配到Android7.0,其中也遇到了不少问题也踩了一些坑,在这里就把我在Android7.0适配上的...

    Android7.0发布已经有一个多月了,Android7.0在给用户带来一些新的特性的同时,也给开发者带来了新的挑战,这几天我将应用适配到Android7.0,其中也遇到了不少问题也踩了一些坑,在这里就把我在Android7.0适配上的一些心得分享给大家,让大家的应用能早一天跑在Android7.0上。

    权限更改

    随着Android版本越来越高,Android对隐私的保护力度也越来越大。从Android6.0引入的动态权限控制(Runtime Permissions)到Android7.0的“私有目录被限制访问”,“StrictMode API 政策”。这些更改在为用户带来更加安全的操作系统的同时也为开发者带来了一些新的任务。如何让你的APP能够适应这些改变而不是cash,是摆在每一位Android开发者身上的责任。

    目录被限制访问

    一直以来,在目录及文件的访问保护方面iOS做的是很到位的,如:iOS的沙箱机制。但,Android在这方面的保护就有些偏弱了,在Android中应用可以读写手机存储中任何一个目录及文件,这也带来了很多的安全问题。现在Android也在着力解决这一问题。

    在Android7.0中为了提高私有文件的安全性,面向 Android N 或更高版本的应用私有目录将被限制访问。对于这个权限的更改开发者需要留意一下改变:

    应对策略:这项权限的变更将意味着你无法通过File API访问手机存储上的数据了,基于File API的一些文件浏览器等也将受到很大的影响,看到这大家是不是惊呆了呢,不过迄今为止,这种限制尚不能完全执行。 应用仍可能使用原生 API 或 File API 来修改它们的私有目录权限。 但是,Android官方强烈反对放宽私有目录的权限。可以看出收起对私有文件的访问权限是Android将来发展的趋势。

    • 给其他应用传递 file:// URI 类型的Uri,可能会导致接受者无法访问该路径。 因此,在Android7.0中尝试传递 file:// URI 会触发 FileUriExposedException。

    应对策略:大家可以通过使用FileProvider来解决这一问题。

    应对策略:大家可以通过ContentResolver.openFileDescriptor()来访问由 DownloadManager 公开的文件。

    应用间共享文件

    在Android7.0系统上,Android 框架强制执行了 StrictMode API 政策禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,应用失败,并出现 FileUriExposedException 异常,如调用系统相机拍照,或裁切照片

    应对策略:若要在应用间共享文件,可以发送 content:// URI类型的Uri,并授予 URI 临时访问权限。 进行此授权的最简单方式是使用 FileProvider类。 如需有关权限和共享文件的更多信息,请参阅共享文件。

    在Android7.0上调用系统相机拍照,裁切照片

    调用系统相机拍照

    在Android7.0之前,如果你想调用系统相机拍照可以通过以下代码来进行:

    File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
    if (!file.getParentFile().exists())file.getParentFile().mkdirs();
    Uri imageUri = Uri.fromFile(file);
    Intent intent = new Intent();
    intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
    startActivityForResult(intent,1006);
    

    Android7.0拍照.png

    在Android7.0上使用上述方式调用系统相拍照会抛出如下异常:

    android.os.FileUriExposedException: file:////storage/emulated/0/temp/1474956193735.jpg exposed beyond app through Intent.getData()
    at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
    at android.net.Uri.checkFileUriExposed(Uri.java:2346)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8933)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:8894)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)
    at android.app.Activity.startActivityForResult(Activity.java:4223)
    ...
    at android.app.Activity.startActivityForResult(Activity.java:4182)
    

    Android7.0拍照闪退.png

    这是由于Android7.0执行了“StrictMode API 政策禁”的原因,不过小伙伴们不用担心,上文讲到了可以用FileProvider来解决这一问题, 现在我们就来一步一步的解决这个问题。

    使用FileProvider

    使用FileProvider的大致步骤如下:
    第一步:在manifest清单文件中注册provider

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.jph.takephoto.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所代表的文件。

    心得:上述代码通过FileProviderUri getUriForFile (Context context, String authority, File file) 静态方法来获取Uri,该方法中authority参数就是清单文件中注册provider的android:authorities="com.jph.takephoto.fileprovider"。 对Web服务器如tomcat,IIS比较熟悉的小伙伴,都只知道为了网站内容的安全和高效,Web服务器都支持为网站内容设置一个虚拟目录,其实FileProvider也有异曲同工之处。

    getUriForFile方法获取的Uri打印出来如下:

    content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg`。  
    

    其中camera_photos就是file_paths.xml中paths的name。

    因为上述指定的path为path="",所以content://com.jph.takephoto.fileprovider/camera_photos/代表的真实路径就是根目录,即:/storage/emulated/0/content://com.jph.takephoto.fileprovider/camera_photos/temp/1474960080319.jpg代表的真实路径是:/storage/emulated/0/temp/1474960080319.jpg

    另外,推荐大家使用开源工具库TakePhoto, TakePhoto是一款在Android设备上获取照片(拍照或从相册、文件中选择)、裁剪图片、压缩图片的开源工具库。

    裁切照片

    在Android7.0之前,你可以通过如下方法来裁切照片:

    File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
    if (!file.getParentFile().exists())file.getParentFile().mkdirs();
    Uri outputUri = Uri.fromFile(file);
    Uri imageUri=Uri.fromFile(new File("/storage/emulated/0/temp/1474960080319.jpg"));
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(imageUri, "image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", 1);
    intent.putExtra("aspectY", 1);
    intent.putExtra("scale", true);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    intent.putExtra("noFaceDetection", true); // no face detection
    startActivityForResult(intent,1008);
    

    和拍照一样,上述代码在Android7.0上同样会引起android.os.FileUriExposedException异常,解决办法就是上文说说的使用FileProvider

    然后,将上述代码改为如下即可:

    File file=new File(Environment.getExternalStorageDirectory(), "/temp/"+System.currentTimeMillis() + ".jpg");
    if (!file.getParentFile().exists())file.getParentFile().mkdirs();
    Uri outputUri = FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider",file);
    Uri imageUri=FileProvider.getUriForFile(context, "com.jph.takephoto.fileprovider", new File("/storage/emulated/0/temp/1474960080319.jpg");//通过FileProvider创建一个content类型的Uri
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.setDataAndType(imageUri, "image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", 1);
    intent.putExtra("aspectY", 1);
    intent.putExtra("scale", true);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    intent.putExtra("noFaceDetection", true); // no face detection
    startActivityForResult(intent,1008);
    

    另外,裁切照片推荐大家使用开源工具库TakePhoto, TakePhoto是一款在Android设备上获取照片(拍照或从相册、文件中选择)、裁剪图片、压缩图片的开源工具库。

    电池和内存

    Android 6.0(API 级别 23)引入了低电耗模式,Android7.0在电池和内存上又做了进一步优化, 来减少Android应用对电量的消耗以及对内存的占用。这些优化所带来的一些规则的变更可能会影响你的应用访问系统资源,以及你的系统通过特定隐式 Intent 与其他应用互动的方式。 所以开发人员需要特别注意这些改变。

    低电耗模式

    在低电耗模式下,当用户设备未插接电源、处于静止状态且屏幕关闭时,该模式会推迟 CPU 和网络活动,从而延长电池寿命。 Android7.0通过在设备未插接电源且屏幕关闭状态下、但不一定要处于静止状态(例如用户外出时把手持式设备装在口袋里)时应用部分 CPU 和网络限制,进一步增强了低电耗模式。

    也就是说,Android7.0会在手机屏幕关闭的状态下,限时应用对CPU以及网络的使用。

    具体规则如下:

    1. 当设备处于充电状态且屏幕已关闭一定时间后,设备会进入低电耗模式并应用第一部分限制: 关闭应用网络访问、推迟作业和同步。
    2. 如果进入低电耗模式后设备处于静止状态达到一定时间,系统则会对PowerManager.WakeLockAlarmManager 闹铃、GPS 和 Wi-Fi 扫描应用余下的低电耗模式限制。 无论是应用部分还是全部低电耗模式限制,系统都会唤醒设备以提供简短的维护时间窗口,在此窗口期间,应用程序可以访问网络并执行任何被推迟的作业/同步。

    后台优化

    小伙伴们都知道在Android中有一些隐式广播,使用这些隐式广播可以做一些特定的功能,如,当手机网络变成WiFi时自动下载更新包等。 但,这些隐式广播会在后台频繁启动已注册侦听这些广播的应用,从而带来很大的电量消耗,为缓解这一问题来提升设备性能和用户体验,在Android 7.0中删除了三项隐式广播,以帮助优化内存使用和电量消耗。

    Android 7.0 应用了以下优化措施:

    • 在 Android 7.0上 应用不会收到 CONNECTIVITY_ACTION 广播,即使你在manifest清单文件中设置了请求接受这些事件的通知。 但,在前台运行的应用如果使用BroadcastReceiver 请求接收通知,则仍可以在主线程中侦听 CONNECTIVITY_CHANGE。
    • 在 Android 7.0上应用无法发送或接收 ACTION_NEW_PICTURE 或ACTION_NEW_VIDEO 类型的广播。

    应对策略:Android 框架提供多个解决方案来缓解对这些隐式广播的需求。 例如,JobScheduler API 提供了一个稳健可靠的机制来安排满足指定条件(例如连入无限流量网络)时所执行的网络操作。 您甚至可以使用 JobScheduler API 来适应内容提供程序变化。

    另外,大家如果想了解更多关于后台的优化可查阅后台优化

    移动设备会经历频繁的连接变更,例如在 Wi-Fi 和移动数据之间切换时。 目前,可以通过在应用清单中注册一个接收器来侦听隐式 CONNECTIVITY_ACTION 广播, 让应用能够监控这些变更。 由于很多应用会注册接收此广播,因此单次网络切换即会导致所有应用被唤醒并同时处理此广播。

    以上是,我在Android7.0上适配上的一些心得,小伙伴们如果有遇到问题可以在下方留言。


    转自:http://www.cboy.me/2016/09/28/Android7.0%E9%80%82%E9%85%8D%E5%BF%83%E5%BE%97/

    展开全文
  • 点击打开链接Android 6.0之后的版本增加了运行时权限,应用程序在执行每个需要系统权限的功能时,需要添加权限请求代码(默认权限禁止),否则应用程序无法响应,测试过程中,发现在android7.0以上的设备上使用...

    本尊在此(Android官方解决方法):点击打开链接

    Android 6.0之后的版本增加了运行时权限,应用程序在执行每个需要系统权限的功能时,需要添加权限请求代码(默认权限禁止),否则应用程序无法响应,

    测试过程中,发现在android7.0以上的设备上使用摄像头时,直接崩溃掉了。原因是android7.0开始,相机拍照的图像保存路径必须在此应用的内部存储文件夹(storage/mounted/0/Android/data/包名//files/pictures文件夹)。需要使用FileProvider获取内部文件的uri

    简单的三句话,无法让TeachCourse真正理解Android 7.0系统权限更改的含义,如果不按照文档的方式去做,API 24开发的应用程序是否就用不了吗?

    出了问题咱们就找问题,下面是详细步骤希望能帮助到你们:

    1,在manifest.xml中加入:

    权限必不可少:

    相机权限、读写权限

    <uses-permission android:name="android.permission.CAMERA"/>

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    然后是:

    <!-- 定义FileProvider -->
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="自己包名.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_provider" />

        </provider>

    2,在res中新建xml文件夹,创建file_provider.xml文件

    <?xml version="1.0" encoding="utf-8"?>  
    <resources>  
        <paths>  
            <external-path  
                name="camera_photos"<!--任意-->  
                path="Android/data/自己包名/files/Pictures" /><!--相机图片保存图片路径,属于APP的存储空间-->  
        </paths>  
      

    </resources>  

    3.代码中使用

    点击事件里面写入就ok:

                    Intent intent = new Intent();
                    intent.setAction("android.media.action.VIDEO_CAPTURE");//录像或者相机
                    intent.addCategory("android.intent.category.DEFAULT");

                      //判断版本

                    if (Build.VERSION.SDK_INT >= 24) {
                        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                        //24以上使用FileProvider
                        intent.putExtra(MediaStore.EXTRA_OUTPUT,
                                FileProvider.getUriForFile(IssueActivity.this, "自己包名.fileprovider", file));
                    }else{
                        //24以下
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
                    }
                    startActivity(intent);

    4.ok


    展开全文
  • 首先来看看 Android7.0对非公开 NDK 库的使用说明。从 Android 7.0 开始,系统将阻止应用动态链接非公开 NDK 库,这种库可能会导致您的应用崩溃。此行为变更旨在为跨平台更新和不同设备提供统一的应用体验。即使您的...

    首先来看看 Android7.0对非公开 NDK 库的使用说明。

    从 Android 7.0 开始,系统将阻止应用动态链接非公开 NDK 库,这种库可能会导致您的应用崩溃。此行为变更旨在为跨平台更新和不同设备提供统一的应用体验。即使您的代码可能不会链接私有库,但您的应用中的第三方静态库可能会这么做。因此,所有开发者都应进行相应检查,确保他们的应用不会在运行 Android 7.0 的设备上崩溃。如果您的应用使用原生代码,则只能使用公开 NDK API。

    您的应用可通过以下三种方式尝试访问私有平台 API:

    您的应用直接访问私有平台库。您应更新您的应用以添加该应用的库副本,或使用公开 NDK API。
    您的应用使用一个可访问私有平台库的第三方库。即使您确定您的应用不会直接访问私有库,您仍应针对此情景测试您的应用。
    您的应用引用一个其 APK 中未包含的库。例如,如果您尝试使用您自己的 OpenSSL 副本,但忘记将它与应用的 APK 进行捆绑,则可能会出现此情况。正常情况下,此应用可在包含 libcrypto.so 的 Android 平台版本上运行。不过,此应用在不包含此库的新版 Android(例如,Android 6.0 和更高的版本)上会崩溃。为修复此问题,请确保您的 APK 捆绑您的所有非 NDK 库。
    

    应用不应使用 NDK 中未包含的原生库,因为这些库可能会发生更改或在不同 Android 版本之间的可用性不同。例如,从 OpenSSL 切换至 BoringSSL 即属于此类更改。此外,由于不属于 NDK 中的平台库没有兼容性要求,因此不同的设备可能提供不同级别的兼容性。

    为降低此限制可能对当前发布的应用的影响,面向 API 级别 23 或更低级别的应用在 Android N 上可暂时访问颇为常用的一组库,例如libandroid_runtime.so、libcutils.so、libcrypto.so 和 libssl.so。如果您的应用加载其中某个库,logcat 会生成一个警告,并在目标设备上显示一个 Toast 来通知您。如果您看到这些警告,您应更新您的应用以添加该应用自己的库副本,或仅使用公开 NDK API。将来发布的 Android 平台可能会完全限制对私有库的使用,并导致您的应用崩溃。

    所有应用在调用既非公开又不可暂时访问的 API 时都会生成一个运行时错误。结果就是 System.loadLibrary 和 dlopen(3) 同时返回 NULL,并可能导致您的应用崩溃。您应检查应用代码以移除对私有平台 API 的使用,并使用预览版设备或模拟器全面测试应用。如果您不确定您的应用是否使用私有库,您可以检查 logcat 以识别运行时错误。


    根据以上的解释,如果自己的应用中用了非公开的 NDK 库,解决这个问题的办法就是:将所用到的.so文件合入armeabi-v7a文件下面即可,这样就能让 apk 运行在 Android7.0的机子上了。

    展开全文
  • 前言Android 7.0已经发布很久了,虽然市场份额还不是很高,但是流行起来都是早晚的事,所以适配Android 7.0刻不容缓。Android 7.0 对系统进行了很多的优化:例如文件访问权限,省电,网络,后台等等,其中最突出的...

    前言

    Android 7.0已经发布很久了,虽然市场份额还不是很高,但是流行起来都是早晚的事,所以适配Android 7.0刻不容缓。

    Android 7.0 对系统进行了很多的优化:例如文件访问权限,省电,网络,后台等等,其中最突出的就是应用外的Uri访问。

    什么时候会用到Uri的应用外访问呢?举一个简单的例子,下载apk更新,这个时候会调用系统功能来安装这个apk,这就是应用外访问文件,需要传入文件的Uri。

    但是这样可能会显得不太安全,万一是什么非常重要的文件就糟糕了,所以Android 7.0对应用外访问的Uri要进行处理加密。

    正文

    那应该怎么处理这个问题呢?首先我们需要注册ContentProvider,这个就很熟悉了,他可以把数据库的内容分享给其他应用,现在是为了分享文件:

    //res目录下创建xml,设置要分享的目录,名称定义file_paths
    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="myFile" path ="" />
    </paths>
    
    // 注册provider
    <provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.lzp.fileprovider"
    android:exported="false"
    // 赋予Uri权限
    android:grantUriPermissions="true">
    
    <meta-data
       android:name="android.support.FILE_PROVIDER_PATHS"
       // 设置要分享的路径
       android:resource="@xml/file_paths"/>
    </provider>

    设置分享的路径有三种:

    <files-path/>代表的根目录: Context.getFilesDir()
    <external-path/>代表的根目录:Environment.getExternalStorageDirectory()
    <cache-path/>代表的根目录: getCacheDir()

    provider注册完了之后,就需要稍微修改一下我们的java代码:

    Intent i = new Intent(Intent.ACTION_VIEW);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    // 判断是否是7.0
    if(Build.VERSION.SDK_INT >= 24){
        // 适配android7.0 ,不能直接访问原路径
        // 需要对intent 授权
        i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        i.setDataAndType(FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider",new File(filePath)),"application/vnd.android.package-archive");
    }
    else{
        i.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive");
    }
    context.startActivity(i);

    在java代码中,我们先判断了当前的手机的系统版本,如果是7.0以下就使用之前的Uri,如果是7.0以上,开始通过Provider来获取加密后的Uri。

    最终得到的Uri的格式:

    content://com.lzp.fileprovider/myFile/xxxxx.apk

    看来主要是把分享出去的路径进行了加密,不能直接看到文件的完整路径。

    总结

    ok,解决这个问题就是这么简单,如果是应用内访问文件是不受影响的,例如我们的读取图片之类的操作,由于时间比较紧,写的就比较简单了,之后再写点稍微高逼格一点的东西。

    有什么问题可以留言哦。

    展开全文
  • 权限更改Android 7.0 做了一些权限更改,这些更改可能会影响您的应用。Android7.1的可以看这篇文章: 《android 7.1悬浮窗系统权限问题》系统权限更改 目录权限 为了提高私有文件的安全性,面向 An
  • Android7.0适配

    2017-03-18 11:01:02
    Android7.0发布已经了,Android7.0在给用户带来一些新的特性的同时,也给开发者带来了新的挑战,这几天我将应用适配到Android7.0,其中也遇到了不少问题也踩了一些坑,在这里就把我在Android7.0适配上的一些心得分享...
  • 应公司项目需求,做了下android 7.0适配。对于我们程序员,适配7.0主要就是对手机本地文件的Uri做转换处理。注意红色字体,意思也就是说对于http开头的等等,非手机存储中的文件就不用管了。Uri.parse("package") ...
  • 适配Android7.0版本更新功能测试手机:华为 Android 7.0 问题1 升级安装失败,程序崩溃:前面有一篇文章讲过了使用DownloadManager在应用内实现版本更新 详见 Android学习之—-利用DownLoadManager实现版本升级,...
  • 最近计划着研究下Android 7.0的系统源码,之前也没做过什么记录,这次正好将学习的内容记录下来,方便以后复习巩固。既然要学习我们的系统源码,那我们第一步要做的就是下载源码并进行编译了。硬件环境要求1. 编译...
  • Android 7.0新签名机制

    2018-06-30 07:23:19
    由于之前的打包机制是采用Python进行打包的,导致打包后的apk在7.0上无法进行安装,特此研究下android7.0的签名机制Android7.0加强了签名的加固,导致在新的签名机制下无法使用修改apk文件的方式进行多渠道打包,...
  • Android 7.0 Nougat 为用户和开发者引入多种新功能。 要详细了解 Android 7.0 的消费者功能,请访问 www.android.com。 多窗口支持 在 Android 7.0 中,我们为该平台引入了一个新的而且非常需要的多任务...
  • Android7.0做了一些权限更改,为了提高私有文件的安全性,面向 Android 7.0 或更高版本的应用私有目录被限制访问。此设置可防止私有文件的原数据泄漏,同事Android7.0如果传递 file:// URI 会触发 ...
  • android 7.0出来了。让你的app准备迎接最新的android版本吧,支持节省电量和内存,这样新的系统行为。使用多窗口UI、直接恢复通知以及其他操作来扩展你的app。 android 7.0介绍了各种各样的新功能给用户和开发者, ...
  • Android7.0发布已经有一个多月了,Android7.0在给用户带来一些新的特性的同时,也给开发者带来了新的挑战,这几天我将应用适配到Android7.0,其中也遇到了不少问题也踩了一些坑,在这里就把我在Android7.0适配上的...
  • 为了提高私有文件的安全性,面向 Android 7.0 或更高版本的应用私有目录被限制访问,详细可以看Google官方的7.0行为变更介绍 (可以直接浏览)。此设置可防止私有文件的元数据泄漏,如它们的大小或存在性。 此权限...
  • 之前看很多修改系统时间得都是4.0之前用的格式,现在7.0之后的格式有所改变,请大家参考比对 建议先用adb命令调试,可以的话在加入代码也一定可以。但要记得 root 和 加权限 /** * 执行Android命令,设置系统时间 ...
  • 由于 Android 7.0 或更高版本的系统在国内手机市场上的占比不是很高,很多 Android 开发人员并没有做 7.0 适配工作,同时测试人员也容易忽视这方面的兼容问题。这导致 7.0 及以上版本的手机用户在使用到应用部分功能...
  • 关于Android7.0的适配时对Notification、拍照、图片的裁剪等问题
1 2 3 4 5 ... 20
收藏数 8,869
精华内容 3,547
关键字:

修改android7.0代码