精华内容
下载资源
问答
  • Android 8.0

    2017-05-14 11:39:34
    Android 8.0

    Android 8.0

    这里写图片描述

    这里写图片描述

    展开全文
  • SELinux for Android 8.0_中文版.doc (Android8.0 sepolicy权限新特性,权限配置指导)
  • 现在已经进入了2018年,Android 8.0系统也逐渐开始普及起来了。三星今年推出的最新旗舰机Galaxy S9已经搭载了Android 8.0系统,紧接着小米、华为、OV等国产手机厂商即将推出的新年旗舰机也会搭载Android 8.0系统。...

    现在已经进入了2018年,Android 8.0系统也逐渐开始普及起来了。三星今年推出的最新旗舰机Galaxy S9已经搭载了Android 8.0系统,紧接着小米、华为、OV等国产手机厂商即将推出的新年旗舰机也会搭载Android 8.0系统。因此,现在已经是时候需要让我们的应用程序对Android 8.0系统进行适配了。

    其实在去年Android 8.0系统刚推出的时候,我就仔细翻阅过Google官方的功能变更文档。变更项着实不少,但是真正需要我们去进行功能适配的地方却并不多。总结了一下,最主要需要进行适配的地方有两处:应用图标和通知栏。那么我们就分为上下两篇来分别对这两处功能适配进行讲解,先从应用图标开始。

    为什么要进行应用图标适配?

    可能有些朋友觉得困惑,应用图标这种东西从Android远古时代就已经有了,而且功能格外的简单,就是放张图片而已,这有什么好适配的呢?但实际上,在当前Android环境下,应用图标功能是极其混乱的。

    如果说要讲一讲手机应用图标的历史,其实要从苹果开始讲起。在上世纪80年代,苹果还在设计Lisa和Macintosh电脑的时候,乔布斯就是个圆角矩形的狂热支持者。当时苹果的工程师写出了一套绝妙的算法,可以在电脑上绘制出圆和椭圆,所有观看者都被震惊了,除了乔布斯,因为乔布斯觉得圆和椭圆虽然也不错,但是如果能绘制出带圆角的矩形就更好了。当时那位工程师觉得这是不可能实现的,而且也完全用不着圆角矩形,能满足基本的绘图需求就可以了。乔布斯愤怒地拉着他走了3条街,指出大街上各种应用圆角矩形的例子,最后那位工程师第二天就做出了绘制圆角矩形的功能。

    因此,在2007年一代iPhone诞生的时候,所有应用程序的图标都毫不出乎意料地使用了圆角矩形图标,即使是第三方应用也被强制要求使用圆角矩形图标,并且这一规则一直延续到了今天的iOS 11当中,如下图所示:

    相反,Android系统在设计的时候就不喜欢苹果这样的封闭与强制,而是选择了自由与开放,对应用图标的形状不做任何强制要求,开发者们可以自由进行选择:

    可以看到,在Android上,应用图标可以是方形、圆形、圆角矩形、或者是其他任意不规则图形。

    本来就是两家公司不同的设计理念,也说不上孰高孰低。但由于Android操作系统是开源的,国内一些手机厂商在定制操作系统的时候就把这一特性给改了。比如小米手机,就选择了向苹果靠拢,强制要求应用图标圆角化。如果某些应用的图标不是圆角矩形的呢?小米系统会自动给它加上一个圆角的效果,如下图所示:

    小米的这种做法看上去是向苹果学习,但实际上是相当恶心的。因为谁都可以看出来,这种自动添加的圆角矩形非常丑,因此很多公司就索性直接将应用的图标都设计成圆角矩形的,正好Android和iOS都用同一套图标还省事了。

    但是这就让Google不开心了,这不是变向强制要求开发者必须将图标设计成圆角矩形吗?于是在去年的Google I/O大会上,Google点名批评了小米的这种做法,说其违反了Android自由和开放的理念。

    除了变向强制要求应用图标圆角化,小米的这种处理方式还有一个弊端,就是如果应用图标的圆角弧度和小米系统要求的不同,那么会出现异常丑陋的效果:

    看到这样的应用图标,真的是一脸尴尬症都要犯了。就因为这两款应用图标的圆角弧度设计得大于了小米系统要求的圆角弧度,就被自动添加上了这样丑陋的白边。

    问题是已经存在了,那么应该怎么解决呢?说实话,这确实是一个长期以来都让人头疼的问题,Google多年来对此也是睁一只眼闭一只眼。终于在Android 8.0系统中,Google下定决心要好好整治一下Android应用图标的规范性了,今天我们就来学习一下。

    8.0系统的应用图标适配

    这个问题对于Google来说还是挺难解决的。因为Google一直在强调自由与开放,那么小米强制要求所有应用图标都必须圆角化也是人家的自由呀,你不准人家这么干是不是本身就违背了自由和开放的理念呢?当然我们在这里讨论这个,有点像讨论先有鸡还是先有蛋的感觉,不过Google还是想出了一套完美的解决方案。

    从Android 8.0系统开始,应用程序的图标被分为了两层:前景层和背景层。也就是说,我们在设计应用图标的时候,需要将前景和背景部分分离,前景用来展示应用图标的Logo,背景用来衬托应用图标的Logo。需要注意的是,背景层在设计的时候只允许定义颜色和纹理,但是不能定义形状。

    那么应用图标的形状由谁来定义呢?Google将这个权利就交给手机厂商了。不是有些手机厂商喜欢学习苹果的圆角图标吗?没问题,由于应用图标的设计分为了两层,手机厂商只需要在这两层之上再盖上一层mask,这个mask可以是圆角矩形、圆形或者是方形等等,视具体手机厂商而定,就可以瞬间让手机上的所有应用图标都变成相同的规范。原理示意图如下:

    可以看到,这里背景层是一张蓝色的网格图,前景层是一张Android机器人Logo图,然后盖上一层圆形的mask,最终就裁剪出了一张圆形的应用图标。

    我一定要适配吗?

    有些朋友可能会觉得这种分成两层的应用图标设计太过于麻烦,不适配可以吗?也有些朋友可能会说,自己的APP并没有做过应用图标适配,在Android 8.0手机上也照样跑得好好的。

    事实上,这个新功能Google是准备让它慢慢过渡的,而不是一次性就强推给所有的开发者。如果你的APP中的targetSdkVersion是低于26的,那么就可以不用进行应用图标适配,Android 8.0系统仍然是向下兼容的。但是如果你将targetSdkVersion指定到了26或者更高,那么Android系统就会认为你的APP已经做好了8.0系统的适配工作,当然包括了应用图标的适配。

    如果你将targetSdkVersion指定到了26,但是却没有进行Android 8.0系统的应用图标适配,那么会出现什么样的效果呢?这里我举几个反面示例:

    这是Google Pixel手机上的截图,操作系统是Android 8.0。可以看到,这两个应用的图标都非常奇怪,本来设计的都是一个圆角矩形的图标,但是却又在外面套上了一个白色的圆圈。为什么会出现这种情况呢?就是因为这两个应用都将targetSdkVersion指定到了26以上,但是却又没有做8.0系统的应用图标适配,而Pixel手机设定的mask是圆形的,所以就自动在应用图标的外层套了一个白色的圆圈。

    由此可以看出,爱奇艺和饿了么这两款应用都是没有在Pixel上进行兼容性测试的。不过考虑到它们都是只在国内市场提供服务,因此也情有可原。

    当然了,国内的Android 8.0手机很快也要开始普及了,我相信没有任何人会希望自己的APP也出现上述的效果,因此下面我们就来开始具体学习,如何进行8.0系统的应用图标适配。

    新建一个项目

    如果有人问我8.0系统应用图标适配到底难不难?这里我会回答,一点都不难。相信所有看完这篇文章的人立马就能学会,但前提是你需要有一个好的工具——Android Studio 3.0或更高版本。

    很高兴告诉大家,Android Studio 3.0中已经内置了8.0系统应用图标适配的功能,如果你已经安装了Android Studio 3.0的话,那么恭喜你,你已经成功了百分之九十了。如果你还在用老版的Android Studio,那么赶快去升级一下,然后再接着看这篇文章。

    好的,那么现在我们就用Android Studio 3.0来新建一个项目,就叫它IconTest吧。

    创建好项目之后,打开app/build.gradle文件检查一下,确保targetSdkVersion已经指定到了26或者更高,如下所示:

    apply plugin: 'com.android.application'

    android {

    compileSdkVersion 26

    defaultConfig {

    applicationId "com.example.icontest"

    minSdkVersion 15

    targetSdkVersion 26

    versionCode 1

    versionName "1.0"

    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    }

    可以看到,这里我在创建新项目的时候默认targetSdkVersion就是26,如果你是低于26的话,说明你的Android SDK有些老了,最好还是更新一下。当然如果你懒得更新也没关系,手动把它改成26就可以了。

    接下来打开AndroidManifest.xml文件,代码如下所示:

    package="com.example.icontest">

    android:allowBackup="true"

    android:icon="@mipmap/ic_launcher"

    android:label="@string/app_name"

    android:roundIcon="@mipmap/ic_launcher_round"

    android:supportsRtl="true"

    android:theme="@style/AppTheme">

    这里我们需要关注的点是android:icon这个属性,通过这个属性,我们将应用的图标指定为了mipmap目录下的ic_launcher文件。另外大家可能注意到还有一个android:roundIcon属性,这是一个只适用在Android 7.1系统上的过渡版本,很快就被8.0系统的应用图标适配所替代了,我们不用去管它。

    刚才说了,应用图标被指定为了mipmap目录下的ic_launcher文件,那么我们快去看下这个文件吧:

    这里虽然目录很多,但是相信任何只要是入了门的Android开发者都能看得懂。唯一需要我们留意的就是mipmap-anydpi-v26这个目录,这个目录表示什么意思呢?就是Android 8.0或以上系统的手机,都会使用这个目录下的ic_launcher来作为图标。

    你会发现,mipmap-anydpi-v26目录下的ic_launcher并不是一张图片,而是一个XML文件,我们打开这个文件看一下,代码如下所示:

    这是一个8.0系统应用图标适配的标准写法,在标签中定义一个标签用于指定图标的背景层,定义一个标签用于指定图标的前景层。

    那么我们分别来看一下背景层和前景层分别都是些什么内容吧,首先打开ic_launcher_background文件,内容如下图所示:

    这是一个使用SVG格式绘制出来的带纹理的底图。当然如果你看不懂这里面的代码也没有关系,因为我也看不懂。SVG格式的图片都是使用AI、PS等图像编辑软件制作之后导出的,基本没有人可以手工编写SVG图片。

    当然,背景层并不是一定要用SVG格式的图片,你也可以使用普通的PNG、JPG等格式的图片,甚至是直接指定一个背景色都可以。

    看完了背景层接着我们来看前景层,打开ic_launcher_foreground文件,内容如下所示:

    类似地,这里也是使用SVG格式绘制出了一个Android机器人的Logo,并且这个机器人还是带投影效果的。当然了,前景层我们也是可以使用PNG、JPG等格式的图片的,待会儿会进行演示。

    好的,现在已经把应用图标相关部分的代码都解释完了,那么这样一个刚刚创建完成的空项目运行起来到底会是什么样的效果呢?我们跑一下看看就知道了,如下图所示:

    可以看到,这就是一个前景层盖在背景层上,然后再被圆形mask进行裁剪之后的效果。

    好的,那么现在剩下的问题就是,我们如何才能对自己的应用图标在Android 8.0系统上进行适配?

    开始适配

    看到爱奇艺的8.0系统应用图标适配工作做得这么差,我就准备拿爱奇艺来做为例子了,我们一起来帮爱奇艺的Android版做个漂亮的应用图标适配吧。

    那么很显然,根据8.0系统的应用图标设计,我们需要准备一个前景层和一个背景层才行。

    前景层也就是爱奇艺的Logo了,这里我通过Photoshop把爱奇艺的Logo图取了出来。

    由于这是一张背景透明的图片,如果直接贴到文章里面就一片白色,啥也看不见了,于是我只好在文章里贴了一张带灰色背景的图片。如果大家需要获取爱奇艺这张前景图的原图,可以点击 这里 获取。

    解决了前景层,接下来我们来看背景层。其实背景层比前景层就简单多了,一般如果没有什么特殊需求的话,背景层直接使用某种纯色就可以了。

    这里我用Photoshop吸取了一下爱奇艺原始应用图标的背景色,值是#04ca00。当然,爱奇艺的背景色并不是完全的纯色,而是有细微的颜色渐变的。不过这里我们只是举例讲解而已,就不追究这些细节了。

    那么现在前景层和背景层都准备好了,接下来我们正式开始进行8.0系统的应用图标适配。重新回到IconTest项目当中,然后按下Windows:Ctrl+Shift+A / Mac:command+shft+A 快捷键,并输入Image Asset,如下所示:

    点击回车键打开Asset Studio编辑器,在这里就可以进行应用图标适配了。

    这个Asset Studio编辑器非常简单好用,一学就会。左边是操作区域,右边是预览区域。

    先来看操作区域,第一行的Icon Type保持默认就可以了,表示同时创建兼容8.0系统以及老版本系统的应用图标。第二行的Name用于指定应用图标的名称,这里也保持默认即可。接下来的三个页签,Foreground Layer用于编辑前景层,Background Layer用于编辑背景层,Legacy用于编辑老版本系统的图标。

    再来看预览区域,这个就十分简单了,用于预览应用图标的最终效果。在预览区域中给出了可能生成的图标形状,包括圆形、圆角矩形、方形等等。注意每个预览图标中都有一个圆圈,这个圆圈叫作安全区域,必须要保证图标的前景层完全处于安全区域当中才行,否则可能会出现图标被手机厂商的mask裁剪掉的情况。

    为了让大家能更加直观地看到操作,这里我使用一张GIF图来演示操作的过程:

    最终,Android Studio会自动帮我们生成适配8.0系统的应用图标,以及适配老版本系统的应用图标,我们甚至一行代码都不用写,一切工作就已经完成了。感兴趣的朋友可以自己到mipmap目录下面去观察一下Android Studio帮我们生成了哪些东西,这里就不带着大家一一去看了。

    最后,让我们来运行一下程序,并且和正版爱奇艺的应用图标放在一起对比一下吧:

    可以看到,做过8.0系统应用图标适配之后,效果明显要好看太多了,也希望爱奇艺的官方APP也能早日完成适配吧。

    总结

    以上所述是小编给大家介绍的Android 8.0系统中应用图标的适配微技巧,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

    展开全文
  • - 针对 Android 8.0 或更高平台版本进行编译,或将 targetSdkVersion 设为 Android 8.0 或更高版本的应用开发者 - 必须修改其应用以正确支持这些行为 提醒窗口 使用 SYSTEM_ALERT_WINDOW 权限的应用无法再使用以下...
    - 针对 Android 8.0 或更高平台版本进行编译,或将 targetSdkVersion 设为 Android 8.0 或更高版本的应用开发者
    - 必须修改其应用以正确支持这些行为
    

    提醒窗口

    使用 SYSTEM_ALERT_WINDOW 权限的应用无法再使用以下窗口类型来在其他应用和系统窗口上方显示提醒窗口:

    • TYPE_PHONE
    • TYPE_PRIORITY_PHONE
    • TYPE_SYSTEM_ALERT
    • TYPE_SYSTEM_OVERLAY
    • TYPE_SYSTEM_ERROR
      相反,应用必须使用名为 TYPE_APPLICATION_OVERLAY 的新窗口类型。

    使用 TYPE_APPLICATION_OVERLAY 窗口类型显示应用的提醒窗口时,请记住新窗口类型的以下特性:

    • 应用的提醒窗口始终显示在状态栏和输入法等关键系统窗口的下面。
    • 系统可以移动使用 TYPE_APPLICATION_OVERLAY 窗口类型的窗口或调整其大小,以改善屏幕显示效果。
    • 通过打开通知栏,用户可以访问设置来阻止应用显示使用 TYPE_APPLICATION_OVERLAY 窗口类型显示的提醒窗口。

    内容变更通知

    Android 8.0 更改了 ContentResolver.notifyChange() 和 registerContentObserver(Uri, boolean, ContentObserver) 在针对 Android 8.0 的应用中的行为方式。

    现在,这些 API 需要在所有 URI 中为颁发机构定义一个有效的 ContentProvider。使用相关权限定义一个有效的 ContentProvider 可帮助您的应用防范来自恶意应用的内容变更,并防止将可能的私密数据泄露给恶意应用。

    视图焦点

    可点击的 View 对象现在默认也可以成为焦点。如果您希望 View 对象可点击但不可成为焦点,请在包含 View 的布局 XML 文件中将 android:focusable 属性设置为 false,或者将 false 传递至应用界面逻辑中的 setFocusable()。

    安全性

    如果您的应用的网络安全性配置选择退出对明文流量的支持,那么您的应用的 WebView 对象无法通过 HTTP 访问网站。每个 WebView 对象必须转而使用 HTTPS。

    有关提升应用安全性的其他准则,请参阅面向 Android 开发者的安全性。

    帐号访问和可检测性

    除非身份验证器拥有用户帐号或用户授予访问权限,否则,应用将无法再访问用户帐号。仅拥有 GET_ACCOUNTS 权限尚不足以访问用户帐号。要获得帐号访问权限,应用应使用 AccountManager.newChooseAccountIntent() 或特定于身份验证器的函数。获得帐号访问权限后,应用可以调用 AccountManager.getAccounts() 来访问帐号。

    Android 8.0 已弃用 LOGIN_ACCOUNTS_CHANGED_ACTION。相反,应用在运行时应使用 addOnAccountsUpdatedListener() 获取帐号更新信息。

    有关新增 API 和增加的帐号访问和可检测性函数的信息,请参阅此文档的“新增 API”部分中的帐号访问和可检测性。

    隐私性

    以下变更影响 Android 8.0 的隐私性。

    系统属性 net.dns1、net.dns2、net.dns3 和 net.dns4 不再可用,此项变更可加强平台的隐私性。
    要获取 DNS 服务器之类的网络连接信息,具有 ACCESS_NETWORK_STATE 权限的应用可以注册 NetworkRequest 或 NetworkCallback 对象。这些类在 Android 5.0(API 级别 21)及更高版本中提供。
    Build.SERIAL 已弃用。需要知道硬件序列号的应用应改为使用新的 Build.getSerial() 函数,该函数要求具有 READ_PHONE_STATE 权限。
    LauncherApps API 不再允许工作资料应用获取有关主个人资料的信息。当某个用户在托管配置文件中时,LauncherApps API 的行为就像同一配置文件组的其他配置文件中未安装任何应用一样。和之前一样,尝试访问无关联的个人资料会引发 SecurityExceptions。
    权限
    在 Android 8.0 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用。

    对于针对 Android 8.0 的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而,一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准。

    例如,假设某个应用在其清单中列出 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE。应用请求 READ_EXTERNAL_STORAGE,并且用户授予了该权限。如果该应用针对的是 API 级别 24 或更低级别,系统还会同时授予 WRITE_EXTERNAL_STORAGE,因为该权限也属于同一 STORAGE 权限组并且也在清单中注册过。如果该应用针对的是 Android 8.0,则系统此时仅会授予 READ_EXTERNAL_STORAGE;不过,如果该应用后来又请求 WRITE_EXTERNAL_STORAGE,则系统会立即授予该权限,而不会提示用户。

    媒体

    框架会执行音频闪避。进行 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 时,应用不会失去焦点。新的 API 适用于需要暂停而不是闪避的应用。请注意,此行为无法在 Android 8.0 1 版本中实现。
    当用户打电话时,活动的媒体流将在通话期间静音。
    所有与音频相关的 API 都应使用 AudioAttributes 而不是音频流类型来说明音频播放用例。仅为音量控制继续使用音频流类型。流类型(例如,已弃用的 AudioTrack constructor)的其他用途仍然有效,但是系统会将其记录为错误。
    使用 AudioTrack 时,如果应用请求了足够大的音频缓冲区,则框架将尝试使用深度缓冲区输出(如果可用)。
    在 Android 8.0 中,媒体按钮事件的处理有所不同:
    在界面操作组件中处理媒体按钮未发生变化:前台操作组件在处理媒体按钮时仍然优先。
    如果前台操作组件不处理媒体按钮,系统会将媒体按钮路由到最近在本地播放音频的应用。在确定哪些应用接收媒体按钮事件时,不再考虑活动状态、标志和媒体会话的播放状态。即使在应用调用 setActive(false) 后,媒体会话仍然可以接收媒体按钮事件。
    如果应用的媒体会话已经释放,系统会将媒体按钮事件发送到应用的 MediaButtonReceiver(如果有)。
    对于任何其他情况,系统都会舍弃媒体按钮事件。与其开始播放错误的应用,不如不播放任何东西。

    原生库

    在针对 Android 8.0 的应用中,如果原生库包含任何可写且可执行的加载代码段,则不会再加载原生库。倘若某些应用的原生库包含不正确的加载代码段,则此变更可能会导致这些应用停止工作

    集合的处理

    • 在 Android 8.0 中,Collections.sort() 是在 List.sort() 的基础上实现的。
    • 在 Android 7.x(API 级别 24 和 25)中,则恰恰相反。在过去,List.sort() 的默认实现会调用 Collections.sort()。

    类加载行为

    Android 8.0 检查确保类加载器在加载新类时不会违反运行时假设条件。不论类引用自 Java(来自 forName())、Dalvik 字节码还是 JNI,都会执行这些检查。平台不会拦截 Java 对 loadClass() 函数的直接调用,也不会检查此类调用的结果。此行为不应影响运行良好的类加载器的正常运行

    反射依旧可以用,只是增加了些检查!
    • 平台检查类加载器返回的类描述符是否与预期的描述符一致。如果返回的描述符与预期不符,平台会引发 NoClassDefFoundError 错误,并在异常日志中存储一条注明不一致之处的详细错误消息。

    • 平台检查请求的类描述符是否有效。此检查捕获间接加载诸如 GetFieldID() 等类的 JNI 调用,向这些类传递无效的描述符。例如,找不到包含 java/lang/String 签名的字段,是因为此签名无效;它应为 Ljava/lang/String;。

    这与 JNI 对 FindClass() 的调用不同,其中 java/lang/String 是一个有效的完全限定名称。

    Android 8.0 不支持多个类加载器同时尝试使用相同的 DexFile 对象来定义类。尝试进行此操作,会导致 Android 运行时引发 InternalError 错误,同时显示消息“Attempt to register dex file with multiple class loaders”。

    DexFile API 现已弃用,强烈建议您改为使用此平台的类加载器之一,包括 PathClassLoader 或 BaseDexClassLoader。
    
    注: 您可以创建多个引用文件系统中同一个 APK 或 JAR 文件容器的类加载器。这样做通常不会占用大量内存:如果存储而不压缩容器中的 DEX 文件,平台可以对此类文件执行 mmap 操作,而不直接提取它们。但是,如果平台必须从容器中提取 DEX 文件,以这种方式引用 DEX 文件可能占用大量内存。
    

    在 Android 中,所有类加载器都被视为支持并行运行。当多个线程争用同一个类加载器加载相同的类时,第一个完成此操作的线程胜出,而操作结果将用于其他线程。无论类加载器是返回同一个类、返回不同的类还是引发异常,都将发生此行为。该平台静默忽略此类异常。

    注意: 在低于 Android 8.0 的平台版本中,违反这些假设条件可能导致多次定义同一个类、由于类混淆造成堆损坏和其他不良影响。
    
    展开全文
  • 1. android 8.0 之前通知 Notification.Builder、 参考博客:https://blog.csdn.net/qi85481455/article/details/82895507 基本案例: public void sendNotification(View view){ // 设置点击通知启动 意图 ...

    1. android 8.0 之前通知    Notification.Builder、

    参考博客:https://blog.csdn.net/qi85481455/article/details/82895507

    基本案例:

    	  public void sendNotification(View view){
            // 设置点击通知启动  意图
            //   Intent intent = new Intent(this,MainActivity.class);
            Intent intent = new Intent();    // 通过通知意图启动拨打电话界面
            intent.setAction(Intent.ACTION_DIAL);
            intent.setData(Uri.parse("tel:"+110));
    
    
    
            PendingIntent pi = PendingIntent.getActivity(MainActivity.this,0,intent,0);
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
    
            Notification.Builder builder=new Notification.Builder(this);
    
            builder.setContentTitle("小标题");
            builder.setContentText("通知内容");
            builder.setSmallIcon(R.mipmap.ic_launcher);   // 小图标
            builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));  // 大图标
            builder.setWhen(System.currentTimeMillis());  //设置时间
            builder.setAutoCancel(true);   // 点击启动Activity以后自动取消
            builder.setContentIntent(pi);
            Notification nf=builder.build();
            nf.flags= Notification.FLAG_INSISTENT;   // 设置以后通知栏不能被取消,不起作用????
            manager.notify(1,nf);    // 1 是通知id 可以根据1  取消通知 
        }

    2. andorid 8.0 以后通知

    参考郭神博客:https://blog.csdn.net/guolin_blog/article/details/79854070

     android 8.0 系统通知问题:通知不能分类,如果关闭通知栏开关以后,那么所有的通知都不能收到
      android 8.0引入到了通知渠道概念,通知分组
    比如把 有聊天 消息、订阅消息,把 聊天消息放入放入一个通知渠道 ,设置高优先级,
    那么这个时候可以关闭订阅消息通知, 
    还可以在通知栏中右滑,设置 再次显示通知时间, 通知通知开关对这个类别

    基本案例:

    package com.notificationdemo.denganzhi;
    
    import android.annotation.TargetApi;
    import android.app.Notification;
    import android.app.NotificationChannel;
    import android.app.NotificationManager;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.BitmapFactory;
    import android.opengl.Visibility;
    import android.os.Build;
    import android.provider.Settings;
    import android.support.v4.app.NotificationCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        String  channelId1 = "chat";
        String  channelId2 = "subscribe";
        
        // 1. 创建通知渠道
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
                String channelName = "聊天消息";
                /***
                 *  通知等级:
                 * NotificationManager.IMPORTANCE_HIGH;
                 * IMPORTANCE_DEFAULT
                 * IMPORTANCE_LOW
                 * IMPORTANCE_MIN
                 */
                int importance = NotificationManager.IMPORTANCE_HIGH;
                createNotificationChannel(channelId1, channelName, importance);
    
    
                channelName = "订阅消息";
                importance = NotificationManager.IMPORTANCE_LOW;
                createNotificationChannel(channelId2, channelName, importance);
            }
        }
        
        @TargetApi(Build.VERSION_CODES.O)
        private void createNotificationChannel(String channelId, String channelName, int importance) {
            NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
            channel.setShowBadge(true);  // 允许显示角标
            NotificationManager notificationManager = (NotificationManager) getSystemService(
                    NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
    
    
        }
    
        // 2.  发送 聊挺通知 ,使用  channelId1 聊天渠道
        public void sendNotifiction1(View view){
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            Notification notification = new NotificationCompat.Builder(this, channelId1)
                    .setContentTitle("收到一条聊天消息")
                    .setContentText("今天中午吃什么?")
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                    .setAutoCancel(true)
                    .setNumber(1000)   // 未读消息
                    .build();
            manager.notify(1, notification);
    
        }
    
    
        // 3. 发送 订阅通知,使用通知渠道 channelId2
        public void sendNotifiction2(View view){
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            Notification notification = new NotificationCompat.Builder(this, channelId2)
                    .setContentTitle("发送一条订阅消息")
                    .setContentText("地铁10号线商铺抢购中!!!!")
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                    .setAutoCancel(true)
                    .build();
            manager.notify(2, notification);
    
        }
    }
    

    问题: 如果用户关闭聊天通知开关,那么用户无法使用通知,动态判断通知栏

    package com.notificationdemo.denganzhi;
    
    import android.annotation.TargetApi;
    import android.app.Notification;
    import android.app.NotificationChannel;
    import android.app.NotificationManager;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.BitmapFactory;
    import android.opengl.Visibility;
    import android.os.Build;
    import android.provider.Settings;
    import android.support.v4.app.NotificationCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        String  channelId1 = "chat";
    
    
        // 1. 创建通知渠道
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
                String channelName = "聊天消息";
                /***
                 *  通知等级:
                 * NotificationManager.IMPORTANCE_HIGH;
                 * IMPORTANCE_DEFAULT
                 * IMPORTANCE_LOW
                 * IMPORTANCE_MIN
                 */
                int importance = NotificationManager.IMPORTANCE_HIGH;
      // 只会调用一次,系统有优化
                createNotificationChannel(channelId1, channelName, importance)
      
            }
        }
    
        @TargetApi(Build.VERSION_CODES.O)
        private void createNotificationChannel(String channelId, String channelName, int importance) {
            NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
            channel.setShowBadge(true);  // 允许显示角标
            NotificationManager notificationManager = (NotificationManager) getSystemService(
                    NOTIFICATION_SERVICE);
            notificationManager.createNotificationChannel(channel);
    
    
        }
    
        public void sendNotifiction3(View view){
            /**
             *   如果 channelId1 通知渠道开关关闭,
             *   比如聊天 功能无法使用
             *   可以通过 Api判断 改通知去掉 开关状态,
             *   如果用户关闭,那么手动去打开
             */
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = manager.getNotificationChannel(channelId1);
                // 获取通知 渠道配置  IMPORTANCE_NONE 表示 关闭通知渠道了
                if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
                    Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
                    intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
                    intent.putExtra(Settings.EXTRA_CHANNEL_ID, channel.getId());
                    startActivity(intent);
                    Toast.makeText(this, "请手动将通知打开", Toast.LENGTH_SHORT).show();
                }
            }
        }
    
    }
    

    3. android8.0  Serivice服务适配

      启动服务:

     MyService bleService=null;
        /* 服务启动 */
        public void showMsg(View view){
            // 启动服务  
            Intent intent = new Intent(MainActivity.this,MyService.class);
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                // android 8.0 启动服务,启动服务以后再5S内必须要调用     startForeground(1, notification); 
                // 否则抛出异常  
                startForegroundService(intent);
            } else {
                // android8.0 之前启动服务
                startService(intent);
            }
    
               bindService(intent, new ServiceConnection() {
    
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    if (service instanceof MyService.MyBinder) {
                        MyService.MyBinder binder = (MyService.MyBinder) service;
                        bleService = binder.getService();
                        Log.e("denganzhi","服务启动成功    " + (bleService == null) );
                    }
                }
                @Override
                public void onServiceDisconnected(ComponentName name) {
    
                }
            }, Context.BIND_AUTO_CREATE);
        }
        // 调用绑定服务中的方法
        public void clickServiceMethod(View view){
            bleService.showHello();
        }

      AndroidManifest.xml 配置

           <service
                android:name=".MyService"
                android:enabled="true"
                android:exported="true"></service>
    
    MyService.java
    public class MyService extends Service {
        private static final String TAG = "denganzhi";
    
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return new MyBinder();
        }
    
        public class MyBinder extends Binder {
            public MyService getService() {
                return MyService.this;
            }
        }
    
        public void showHello(){
            Log.e("denganzhi","showHello    :showHello"  );
        }
    
    
        @Override
        public void onCreate() {
            super.onCreate();
    
    
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, final int startId) {
            int type = intent.getIntExtra("type",1);
            Log.e(TAG, "the create notification type is " + type + "----" + (type == 1 ? "true" : "false"));
    
    
            // 发送基本通知
            //    createNotificationChannel0001
    
    
            //Android 图片产长图、大图通知;https://blog.csdn.net/SDBX_lyp/article/details/80157222
            createNotificationChannel();;
    
            return super.onStartCommand(intent, flags, startId);
        }
    
    
    
        // 普通通知,只有title 和 context , 一行内容无法展开
        private void createNotificationChannel0001() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Log.e(TAG, "createNotificationChannel");
                NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                // 通知渠道的id
                String id = "kaadas";
                // 用户可以看到的通知渠道的名字.
                CharSequence name = "Bluetooth lock notifications";
    //         用户可以看到的通知渠道的描述
                String description = "If you are using a Bluetooth lock, do not turn off notifications";
                int importance = NotificationManager.IMPORTANCE_HIGH;
                NotificationChannel mChannel = new NotificationChannel(id, name, importance);
    //         配置通知渠道的属性
                mChannel.setDescription(description);
    //         设置通知出现时的闪灯(如果 android 设备支持的话)
                mChannel.enableLights(true);
                mChannel.setLightColor(Color.RED);
    //         设置通知出现时的震动(如果 android 设备支持的话)
                //         mChannel.enableVibration(true);
                ///         mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
    //         最后在notificationmanager中创建该通知渠道 //
                mNotificationManager.createNotificationChannel(mChannel);
    
                // 为该通知设置一个id
                //    int notifyID = 1;
                // 通知渠道的id
                //    String CHANNEL_ID = "my_channel_01";
                // Create a notification and set the notification channel.
                Notification notification = new Notification.Builder(this)
                        //  .setContentTitle("通知栏Title") .setContentText("通知栏Text")
                        .setContentTitle("Bluetooth lock notifications").
                                setContentText("If you are using a Bluetooth lock, do not turn off notifications")
                        .setSmallIcon(R.drawable.ic_launcher_foreground)
                        .setChannelId(id)
                        .build();
                startForeground(1, notification);
            }
        }
    
        /**
         *   Android 图片产长图、大图通知;https://blog.csdn.net/SDBX_lyp/article/details/80157222
         *
         */
        private void createNotificationChannel() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Log.e("denganzhi1", "createNotificationChannel");
                android.app.NotificationManager mNotificationManager = (android.app.NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                // 通知渠道的id
                String id = "kaadas";
                // 用户可以看到的通知渠道的名字.
                CharSequence name = "Bluetooth lock notifications";
    //         用户可以看到的通知渠道的描述
                String description = "If you are using a Bluetooth lock, do not turn off notifications";
                int importance = android.app.NotificationManager.IMPORTANCE_HIGH;
                NotificationChannel mChannel = new NotificationChannel(id, name, importance);
    //         配置通知渠道的属性
                mChannel.setDescription(description);
    //         设置通知出现时的闪灯(如果 android 设备支持的话)
                mChannel.enableLights(true);
                mChannel.setLightColor(Color.RED);
    //         设置通知出现时的震动(如果 android 设备支持的话)
                //         mChannel.enableVibration(true);
                ///         mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
    //         最后在notificationmanager中创建该通知渠道 //
                mNotificationManager.createNotificationChannel(mChannel);
    
                // 为该通知设置一个id
                //    int notifyID = 1;
                // 通知渠道的id
                //    String CHANNEL_ID = "my_channel_01";
                // Create a notification and set the notification channel.
                Intent startIntent = new Intent(this,MainActivity.class);
    
                PendingIntent pi = PendingIntent.getActivity(this,0,startIntent,0);
    
                Notification notification = new NotificationCompat.Builder(this)
                        //  .setContentTitle("通知栏Title") .setContentText("通知栏Text")
                        //  .setContentTitle("通知栏Title") .setContentText("通知栏Text"
                        .setContentTitle(getString(R.string.kaadas_notification))
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                        .setChannelId(id)
                        .setContentIntent(pi)
                        .setOnlyAlertOnce(true)
                        .setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.kaadas_notification_open)))
                        .build();
    
    
    
                startForeground(1, notification);
            }
        }
    
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            stopForeground(true);
        }
    }

     

    展开全文
  • Android O 迁移(适配Android 8.0)现在我们介绍下 Android O新的改动:通知在 Android 8.0 中,我们已重新设计通知,以便为管理通知行为和设置提供更轻松和更统一的方式。这些变更包括:Android 8.0 中的通知长按...
  • 公司项目Android8.0适配分析1. 官方推荐的兼容测试方式 2. Android8.0行为变更说明 Android 8.0 行为变更包括两个部分:针对所有 API 级别的应用和针对 Android 8.0 的应用(8.0专属部分大部分用不到,所以没...
  • Android 8.0 系统,Google引入通知渠道,提高用户体验,方便用户管理通知信息,同时也提高了通知到达率。 通知适配 Android 8.0 功能和 API 配置 build.gradle 中targetSdkVersion设置大于等于26。这时如果不对...
  • android8.0 SDK包android26

    2017-11-03 10:12:30
    anroid8.0 SDK包,编译android8.0必备工具,移植android8.0必备工具
  • Android 8.0 中的 ART 功能改进在 Android 8.0 版本中,Android Runtime (ART) 有了极大改进。下面的列表总结了设备制造商可以在 ART 中获得的增强功能。并发压缩式垃圾回收器正如 Google 在 Google I/O 大会上所...
  • DolbyAtmo Dolby 杜比音乐安卓8.0android8.0可以使用,可以定制ROM的时候使用。也可以直接卡刷,android8.0可用.本人在小米6上使用没有问题.已经精简掉视频文件,
  • 这是Android8.0的问题,其他版本问题 先看下源码 if (ActivityInfo.isFixedOrientation(requestedOrientation) // 是否锁定了屏幕方向 && !fullscreen // 不是全屏 && appInfo.targetSdkVersion &...
  • Android8.0 WiFi热点适配在Android8.0上用以前的方式调试WiFi热点的时候发现无法正常开启热点,于是查了下,发现之前的热点打开接口已经废弃。原先的接口WifiManager.java中setWifiApEnabled方法用来打开WiFi热点...
  • DolbyAtmo Dolby 杜比音乐安卓 8.0 android8.0 可以使用。 DolbyAtmo Dolby 杜比音乐安卓8.0android8.0可以使用,可以定制ROM的时候使用。也可以直接卡刷,android8.0可用.本人在小米6上使用没有问题.已经精简掉视频...
  • Android 8.0 系统自带 Settings Android 8.0 系统自带 Settings
  • Android 8.0 系统自带 WallpaperPicker Android 8.0 系统自带 WallpaperPicker
  • Android 8.0 系统自带 DeskClock Android 8.0 系统自带 DeskClock
  • Android 8.0 系统自带 Calendar Android 8.0 系统自带 Calendar
  • Android 8.0 系统自带 SnapdragonGallery Android 8.0 系统自带 SnapdragonGallery
  • 概述参考资料《一起来学习Android 8.0系统的应用图标适配吧》中已经讲得很清楚了,这里我只是简单总结下。详情的内容请阅读参考资料!为什么进行图标适配?可能有些朋友觉得困惑,应用图标这种东西从Android远古时代...
  • Android 7.0 &amp;&amp;7.1:adb shell dumpsys activity activities | findstr mFocusedActivityAndroid 8.0 : adb shell dumpsys activity activities | findstr mResumedActivity
  • SDK Android 8.0 (API 26)

    2018-07-18 10:15:16
    SDK Android 8.0 (API 26) SDK Android 8.0 (API 26) SDK Android 8.0 (API 26)
  • Android 8.0 Launcher开发指南.
  • 官网:https://developer.android.com/about/versions/oreo/android-8.0-migration.html向 Android 8.0 迁移应用本文内容确保平台兼容性准备一台运行 Android 8.0 的设备执行兼容性测试构建具有 Android 8.0 功能的...
  • Android 8.0指纹验证

    2018-11-19 10:56:11
    Android 8.0指纹验证,前提必须已经设置了指纹信息,才能进行操作,代码里面都有验证,欢迎下载
  • UiAutomatorviewer 源码对应 Android 8.0。 UiAutomatorviewer 的源码,对应 Android 8.0 版本 。 uiautomator
  • Android 8.0 Settings流程分析与变动2018年03月12日 18:38:18阅读数:1102开! 场! 白! 好! 难! 写!一,相比Android Settings 7.0 如下图,在7.0的基础上,去掉了7.0新加的侧滑菜单(可能是觉得有点鸡肋吧)。...
  • Android 8.0 适配

    2018-10-25 16:28:13
    Android O (8.0)(API 26) 适配 最近将我们项目的targetSdkVersion升到26了,下面是一些需要适配的问题,后面遇到其他问题再补充: 一、参考我另一篇文章 Android 8.0 通知适配 二、安装APK 1、在Android 8.0及以上...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,483
精华内容 4,193
关键字:

android8.0