Google I/O大会:Android 13
3个体验升级的方向以智能手机为场景核心、 扩大智能终端的应用边界以及实现多设备间更好地协同。具体到系统体验层,安卓13将支持图标颜色随主题更换、为不同应用设定使用的语言、新的媒体中心界面等等,同时谷歌也推出了自家的钱包应用(Google Wallet)。升级内容谷歌优化了平板的安卓体验,通知栏面积变得更大,任务栏也得到了改进,时刻固定在平板底部。通过任务栏,你可以方便的分屏,拖动照片进行分享。谷歌地图、消息应用、音乐等等多有了全新设计,更加适合平板使用。而对于第三方应用,谷歌也表示,它们会更加精美易用。谷歌还介绍了安卓多设备间的合作与互联互通,比如你的手机收到信息,可以在平板上同步回复;手机复制,到平板粘贴;无线耳机和智能手机间的配对变得更加简单。谷歌公布了全新的安卓平板,并承诺为谷歌服务推出20多个安卓平板电脑应用.这款平板电脑采用宽屏设计,背面拥有四个pogo-pin连接器。同时,谷歌还展示了一款AR护目镜,但目前正处于概念阶段,仅展现了翻译功能。在演示中,该设备会在屏幕上显示翻译后的文本,外观像是一副标准的粗框眼镜。。这更多地是为开发者们指明了未来的方向,因为目前安卓系统在大屏端的体验距离隔壁的iPad OS仍有非常大的差距,当苹果已经开始联合厂商针对iPad推出专业应用的时候,谷歌还在优化最常见的视频应用。硬件方面,谷歌Pixel6a共有三种配色,搭载了谷歌Tensor处理器+Titan M2安全芯片,并且支持5G网络连接;该机配备6.1英寸OLED屏幕,分辨率为2400×1080,支持60Hz,存储空间为6GB+128GB,内置4300mAh电池。该机将获得“五年的安全更新”和三年的操作系统更新,并将于7月28日上线,7月21日开始预订,售价449美元。谷歌也同时更新了自家的TWS(真无线蓝牙耳机)产品线,推出了Pixel Buds Pro,该产品最大特点在于支持了主动降噪功能,内部采用谷歌开发的6核心音频处理芯片。搭配谷歌的定制音频芯片和波束成形麦克风,可以确保音频更加清晰。该耳机支持多点连接,可以连接到多个设备,并且可以在设备之间无缝切换,而无需使用蓝牙菜单连接或断开耳机。续航方面,Pixel Buds Pro在降噪模式下续航为7小时,搭配充电盒续航长达20小时,关闭降噪模式下续航为11小时。该耳机售价199美元,并在7月21日接受预定。谷歌Pixel Watch也在大会亮相,该手表侧面配备可旋转表冠,机身为不锈钢,表带可拆卸;支持NFC触碰付款,内置Google Home;搭载Wear OS,集成Fitbit,拥有Google Assistant功能,并且将有一个LTE选项。
2021年互联网+发展研究报告
第一章 行业发展概况互联网+是指在创新2.0(信息时代、知识社会的创新形态)推动下由互联网发展的新业态,也是在知识社会创新2.0推动下由互联网形态演进、催生的经济社会发展新形态。“互联网+”简单的说就是“互联网+传统行业”,随着科学技术的发展,利用信息和互联网平台,使得互联网与传统行业进行融合,利用互联网具备的优势特点,创造新的发展机会。“互联网+”通过其自身的优势,对传统行业进行优化升级转型,使得传统行业能够适应当下的新发展,从而最终推动社会不断地向前发展。互联网+是互联网思维的进一步实践成果,推动经济形态不断地发生演变,从而带动社会经济实体的生命力,为改革、创新、发展提供广阔的网络平台。它代表一种新的社会形态,即充分发挥互联网在社会资源配置中的优化和集成作用,将互联网的创新成果深度融合于经济、社会各域之中,提升全社会的创新力和生产力,形成更广泛的以互联网为基础设施和实现工具的经济发展新形态。2015年7月4日,国务院印发《国务院关于积极推进“互联网+”行动的指导意见》。2020年5月22日,国务院总理李克强在发布的2020年国务院政府工作报告中提出,全面推进“互联网+”,打造数字经济新优势。截至2020年12月,我国网民规模为9.89亿,较2020年3月新增网民8540万,互联网普及率达70.4%,较2020年3月提升5.9个百分点。图 网民规模和互联网普及率资料来源:资产信息网 千际投行 中国互联网信息中心中国互联网信息中心指出,新冠肺炎疫情加速推动了从个体、企业到政府全方位的社会数字化转型浪潮。在个体方面,疫情的隔离使个体更加倾向于使用互联网连接,用户上网意愿、上网习惯加速形成。网民个体利用流媒体平台和社交平台获取信息,借助网络购物、网上外卖解决日常生活所需,通过在线政务应用和健康码办事出行,不断共享互联网带来的数字红利。在企业方面,疫情的出现为企业数字化转型按下了“加速键”,在线办公、在线交易等线上化运营方式为企业在特殊时期保持正常运转提供了支撑。在政府方面,政府的数字化应急能力和在线政务服务能力在疫情下不断“淬炼”,在线服务指数由全球第34位跃升至第9位,迈入全球领先行列30。深刻的数字化转型正在成为全社会应对未来不确定性的重要抓手。第二章 商业模式和收入模式2.1 产业链价值链“互联网+”代表着一种新的经济形态,它指的是依托互联网信息技术实现互联网与传统产业的联合,以优化生产要素、更新业务体系、重构商业模式等途径来完成经济转型和升级。“互联网+”计划的目的在于充分发挥互联网的优势,将互联网与传统产业深入融合,以产业升级提升经济生产力,最后实现社会财富的增加。互联网应用可以分为基础应用类、商务交易类、网络娱乐类、公共服务类。其支持技术被包含在计算机产业链中。图 计算机产业链资料来源:资产信息网 千际投行 iFinD“互联网+”概念的中心词是互联网,它是“互联网+”计划的出发点。“互联网+”计划具体可分为两个层次的内容来表述。一方面,可以将“互联网+”概念中的文字“互联网”与符号“+”分开理解。符号“+”意为加号,即代表着添加与联合。这表明了“互联网+”计划的应用范围为互联网与其他传统产业,它是针对不同产业间发展的一项新计划,应用手段则是通过互联网与传统产业进行联合和深入融合的方式进行。另一方面,“互联网+”作为一个整体概念,其深层意义是通过传统产业的互联网化完成产业升级。互联网通过将开放、平等、互动等网络特性在传统产业的运用,通过大数据的分析与整合,试图理清供求关系,通过改造传统产业的生产方式、产业结构等内容,来增强经济发展动力,提升效益,从而促进国民经济健康有序发展。比如工业互联网、智慧医疗、智慧政务、智慧物流、智慧家居等行业的发展深受“互联网+”的影响。图 5G产业链资料来源:资产信息网 千际投行 iFinD图 大数据产业链中的行业应用资料来源:资产信息网 千际投行 iFinD2.2 商业模式2.2.1 互联网+的特征互联网+有六大特征,即跨界融合、创新驱动、重塑结构、尊重人性、开放生态、连接一切。(1) 跨界融合+就是跨界,就是变革,就是开放,就是重塑融合。敢于跨界了,创新的基础就更坚实;融合协同了,群体智能才会实现,从研发到产业化的路径才会更垂直。融合本身也指代身份的融合,客户消费转化为投资,伙伴参与创新,等等,不一而足。(2) 创新驱动中国粗放的资源驱动型增长方式早就难以为继,必须转变到创新驱动发展这条正确的道路上来。这正是互联网的特质,用所谓的互联网思维来求变、自我革命,也更能发挥创新的力量。(3) 重塑结构信息革命、全球化、互联网业已打破了原有的社会结构、经济结构、地缘结构、文化结构。权力、议事规则、话语权不断在发生变化。互联网+社会治理、虚拟社会治理会是很大的不同。(4) 尊重人性人性的光辉是推动科技进步、经济增长、社会进步、文化繁荣的最根本的力量,互联网的力量之强大最根本地也来源于对人性的最大限度的尊重、对人体验的敬畏、对人的创造性发挥的重视。例如UGC,例如卷入式营销,例如分享经济。(5) 开放生态关于互联网+,生态是非常重要的特征,而生态的本身就是开放的。我们推进互联网+,其中一个重要的方向就是要把过去制约创新的环节化解掉,把孤岛式创新连接起来,让研发由人性决定的市场驱动,让创业并努力者有机会实现价值。(6) 连接一切连接是有层次的,可连接性是有差异的,连接的价值是相差很大的,但是连接一切是互联网+的目标。2.2.2 互联网+的多视角(1) 消费模式“互联网+”背景下的消费模式完全不同于传统消费模式,对商品生产、市场流通、经营销售都产生了巨大的影响,合成了消费模式的新常态。一是“互联网+”间接上促进了消费个性化趋势的形成,消费者成为了商品和服务的生产出发点与归宿,与生产有了直接紧密的联系。二是互联网信息技术有助于实现空间分散、时间错位之间的供求匹配,从而可以更好地提高供求双方的福利水平,进而优化升级人们的基本需求。三是网络技术的发展使得各种类型信息排山倒海般地被消费者接收到,信息的传播同样不受时空地域的限制,同时借助于大数据技术,消费者的消费偏好、消费习惯等微观信息也被归纳统计,生产方更能借助于这些数据为消费者提供完善的服务,消费信息在生产与消费方的充分流动促使整个互联网消费稳步健康发展。四是互联网的时效性、综合性、互动性和使用便利性使得消费者能方便地对商品的价格、性能、使用感受进行分享,消费者“货比三家”的困难程度被大大降低。这种信息体验对消费模式转型发挥着越来越重要的影响。五是“互联网+”的消费时代最大限度地扩大了消费增量、盘活了消费存量,强化了消费者自由选择、自主消费的系列权益。(2) 工业行业“互联网+工业”即传统制造业企业采用移动互联网、云计算、大数据、物联网等信息通信技术,改造原有产品及研发生产方式,与“工业互联网”、“工业4.0”的内涵一致。(3) 金融行业互联网+金融从组织形式上看,这种结合至少有三种方式:第一种是互联网公司做金融,如果这种现象大范围发生,并且取代原有的金融企业,那就是互联网金融颠覆论;第二种是金融机构的互联网化;第三种是互联网公司和金融机构合作。业务范围有互联网供应链金融、众筹、互联网银行、不良资产的互联网处置服务平台。(4) 商贸行业2015中国化妆品零售大会在上海召开,600位化妆品连锁店主,百余位化妆品代理商,数十位国内外主流品牌代表与会。面对实体零售渠道变革,会议提出了“零售业+互联网”的概念,建议以产业链最终环节零售为切入点,结合国家战略发展思维,发扬“+”时代精神,回归渠道本质,以变革来推进整个产业提升。2020年,国家统计局公布了一季度主要经济数据,实物商品网上零售额18536亿元,增长5.9%,其中吃类和用类商品分别增长32.7%和10%。直播带货表现强劲,成新消费造风口。直播为商家带来的成交订单数同比增长超过160%,新开播商家同比增长近3倍。(5) 互联网+智慧城市所谓“互联网+”,实际上是创新2.0下的互联网发展新形态、新业态,是知识社会创新2.0推动下的互联网形态演进。而智慧城市则是新一代信息技术支撑、知识社会下一代创新(创新2.0)环境下的城市形态。“互联网+”也被认为是创新2.0时代智慧城市的基本特征,有利于形成创新涌现的智慧城市生态,从而进一步完善城市的管与运行功能,实现更好的公共服务,让人们生活更便宜、出行更便利、环境更宜居。(6) 交通出行“互联网+交通”已经在交通运输领域产生了“化学效应”,比方说,大家经常使用的打车软件、网上购买火车和飞机票、出行导航系统等等。从国外的Uber、Lyft到国内的滴滴打车、快的打车,移动互联网催生了一批打车拼车专车软件,虽然它们在全世界不同的地方仍存在不同的争议,但它们通过把移动互联网和传统的交通出行相结合,改善了人们出行的方式,增加了车辆的使用率,推动了互联网共享经济的发展,提高了效率、减少了排放,对环境保护也做出了贡献。(7) 旅游行业互联网+使得微信可以实现微信购票、景区导览、规划路线等功能。腾讯云可以帮助建设旅游服务云平台和运行监测调度平台。市民在景区门口,不用排队,只要在景区扫一扫微信二维码,即可实现微信支付。购票后,微信将根据市民的购票信息,进行智能线路推送。而且,微信电子二维码门票自助扫码过闸机,无需人工检票入园。(8) 医疗行业互联网将优化传统的诊疗模式,为患者提供一条龙的健康管理服务。在传统的医患模式中,患者普遍存在事前缺乏预防,事中体验差,事后无服务的现象。而通过互联网医疗,患者有望从移动医疗数据端监测自身健康数据,做好事前防范;在诊疗服务中,依靠移动医疗实现网上挂号、询诊、购买、支付,节约时间和经济成本,提升事中体验;并依靠互联网在事后与医生沟通。百度、阿里、腾讯先后出手互联网医疗产业,形成了巨大的产业布局网,他们利用各自优势,通过不同途径实现着改变传统医疗行业模式的梦想。(9) 农业行业农业是中国最传统的基础产业,亟需用数字技术提升农业生产效率,通过信息技术对地块的土壤、肥力、气候等进行大数据分析,然后据此提供种植、施肥相关的解决方案,大大提升农业生产效率。此外,农业信息的互联网化将有助于需求市场的对接,互联网时代的新农民不仅可以利用互联网获取先进的技术信息,也可以通过大数据掌握最新的农产品价格走势,从而决定农业生产重点。与此同时,农业电商将推动农业现代化进程,通过互联网交易平台减少农产品买卖中间环节,增加农民收益。面对万亿元以上的农资市场以及近七亿的农村用户人口,农业电商面临巨大的市场空间。2.2.3 收入成本分析以互联网+不同行业中三家上市公司的进行收入成本分析。表 工业富联(601138.SH)收入成本分析(亿元)资料来源:资产信息网 千际投行 东方财富网表 苏宁易购(002024.SZ)收入成本分析(亿元)资料来源:资产信息网 千际投行 东方财富网表 海尔智家(600690.SH)收入成本分析(亿元) 资料来源:资产信息网 千际投行 东方财富网2.3 技术发展互联网新兴技术包括量子科技、区块链、人工智能、基础资源技术。2.3.1 量子科技近年来,以量子计算、量子通信和量子测量为代表的量子科技研究与应用在全球范围内加速发展,各国纷纷加大投入力度,拓宽项目布局。一是我国加强量子科技领域政策布局和配套扶持力度。二是量子科技技术标准化研究快速发展,论文和专利数量增长迅速。一方面,我国在量子保密通信网络建设和试点应用方面具备较好的研究基础和时间积累,相关标准化研究工作也逐步开展。2017年,中国通信标准化协会成立量子通信与信息技术特设任务组,开展量子通信、网络及量子信息技术关键器件的标准研究,目前已完成6项研究报告125。2019年1月,量子计算与测量标准化技术委员会正式成立,开展量子计算和量子测量领域的标准化研究工作。另一方面,我国量子信息技术创新持续加快,论文和专利数量不断增长。从发表论文研究机构来看,我国量子通信论文量位列全球第一,超过4000篇,在全球发文量前25中有10家是中国高校或科研单位;从专利申请和授权数量看,中美两国均保持领先。三是量子科技研发与应用不断深入,产业化探索处于初步发展阶段。在量子计算领域,量子计算云平台成为热点。我国量子计算云平台虽起步较晚,但目前发展态势良好,与国际先进水平相比在量子处理器、量子计算软件方面的差距逐步缩小。2.3.2 区块链一是标准体系建设完善。2020年4月,全国区块链和分布式记账技术标准化技术委员会组建,以建设完备的区块链标准体系、更好服务区块链技术产业发展。截至2020年12月,我国已实施2个区块链行业标准以及10个区块链地方标准130。二是专利数量增长显著。根据中国国家识产权局专利局的统计检索,截至2020年12月,我国国内提交的区块链发明专利申请公开数量达14013个131,较2019年底增加5341个。截至2020年11月,PCT专利数中,华为申请数量位列全球第二,为150件132。三是底层技术有所创新。吞吐率和可伸缩性一直以来都是制约区块链开展大规模应用的瓶颈,基于有向无环图(Directed AcyclicGraph,DAG)和基于分区(Sharding)的两类解决方案的区块链系统有望打破这一难题。目前已有多种系统投入运行或进入实验阶段,如由王嘉平博士研究提出的Monoxide133等,尝试解决当前区块链技术在系统层面的主要问题,在保证去中心化和安全性的前提下大幅度提高性能。2.3.3 人工智能在人工智能方面,产业智能化升级的巨大空间带动我国人工智能应用迅猛发展。我国在制造、交通、金融、医疗、教育等传统行业的发展相对于发达国家而言,产业发展程度和基础设施水平都有较大的改造和提升空间,为新一代人工智能应用层产业加速落地提供了广阔的市场。2.3.4 基础资源技术一是国家互联网基础资源大数据(服务)平台持续完善。2020年,我国发布了国家互联网基础资源大数据(服务)平台二期。自2018年9月国家互联网基础资源大数据(服务)平台一期发布以来,经过一期和二期工程的持续研发与建设,国家互联网基础资源大数据(服务)平台已初步形成涵盖数据采集、清洗、汇聚、管理、分析、挖掘、安全保障等环节在内的互联网基础资源领域全链条大数据技术能力。二是互联网基础资源管理服务平台融合创新。2020年,我国发布了“网域链”--基于区块链的互联网基础资源管理服务(实验)平台。该平台采取的新型域名解析架构在技术、效率、监管和兼容等方面都进行了创新。2.4 政策和监管互联网和相关服务行业的主管部门包括工信部、商务部和国家工商行政管理总局。互联网+其他产业也受到其他行业主管部门的监管。2.4.1 工信部负责互联网行业管理(含移动互联网);协调电信网、互联网、专用通信网的建设,促进网络资源共建共享;指导电信和互联网相关行业自律和相关行业组织发展;电信网、互联网网络与信息安全技术平台的建设和使用管理;拟订电信网、互联网数据安全管理政策、规范、标准并组织实施等。2.4.2 商务部负责推进流通产业结构调整,指导流通企业改革、商贸服务业和社区商业发展,推动流通标准化和连锁经营、商业特许经营、物流配送、电子商务等现代流通方式的发展。其下属的电子商务和信息化司负责制定我国电子商务发展规划,拟订推动企业信息化、运用电子商务开拓国内外市场的相关政策措施并组织实施;支持中小企业电子商务应用,促进网络购物等面向消费者的电子商务的健康发展;拟订电子商务相关标准、规则;组织和参与电子商务规则和标准的对外谈判、磋商和交流;推动电子商务的国际合作等。2.4.3 国家工商行政管理总局负责监督管理市场交易行为和网络商品交易及有关服务的行为。2.4.4 行业自律组织有中国电子商务协会和中国互联网协会是互联网和相关产业的协会。(1) 中国电子商务协会主要负责辅助政府决策,推动电子商务的发展;进行与电子商务相关业务的调查和研究,协助政府部门制定相关法律法规和政策;开展电子商务国际交流与合作,进行电子商务立法研究,推进信用体系建设。(2) 中国互联网协会主要负责制订并实施互联网行业自律规范和公约,发挥行业自律作用,维护国家网络与信息安全、行业整体利益和用户权益;经政府主管部门批准、授权或委托,制订互联网行业标准与规范,开展行业信用评价、资质及职业资格审核、奖项评选和申报推荐等工作。2.4.5 行业相关政策有《电子商务模式规范》《网络交易服务规范》《“十三五”国家战略性新兴产业发展规划》《中华人民共和国网络安全法》《关于深化“互联网+先进制造业”发展工业互联网的指导意见》《“互联网+流通”行动计划》《关于促进互联网金融健康发展的指导意见》《国务院办公厅关于促进农村电子商务加快发展的指导意见》《关于加大对新消费领域金融支持的指导意见》《信息化和工业化融合发展规划(2016-2020)》《关于深化“互联网+先进制造业”发展工业互联网的指导意见》。第三章 行业估值和全球龙头企业3.1 行业综合财务分析和估值方法图 互联网+[HK]指数历史PE/PB资料来源:千际投行 资产信息网 iFinD互联网+[HK]指数估值方法可以选择市盈率估值法、PEG估值法、市净率估值法、市现率、P/S市销率估值法、EV / Sales市售率估值法、RNAV重估净资产估值法、EV/EBITDA估值法、DDM估值法、DCF现金流折现估值法、NAV净资产价值估值法等。表 互联网+[HK]部分上市公司的估值指标资料来源:千际投行 资产信息网 iFinD3.2 行业发展和价格驱动机制及风险管理2020年我国个人互联网应用增长较为平稳。其中,短视频、网络支付和网络购物的用户规模增长最为显著,增长率分别为12.9%、11.2%和10.2%。基础类应用中,即时通信、搜索引擎保持平稳增长态势,用户规模较2020年3月分别增长9.5%、2.6%。网络娱乐类应用中,网络直播保持快速增长,增长率为10.2%;网络视频、网络音乐的用户规模较2020年3月分别增长 9.0%、3.6%。表 2020.03-2020.12网民各类互联网应用用户规模和使用率资料来源:资产信息网 千际投行 中国互联网信息中心3.3 竞争分析和典型公司复盘3.3.1 竞争分析iFinD互联网+[HK]指数共有31家上市公司,按照总市值从高到低排序,可以得到如下表所示的排名。表 互联网+[HK]指数上市公司资料来源:资产信息网 千际投行 iFinD3.4 中国重要竞争者表 部分互联网+板块上市公司资料来源:资产信息网 千际投行 iFinD(1) 腾讯(OTCMKTS:TCEHY、港交所:00700):腾讯控股有限公司(简称腾讯)Tencent Holdings Limited创立于1998年11月,总部位于中国深圳,全职雇员85,858人,是中国三大互联网集团公司(百度、阿里、腾讯,合称BAT)之一,是目前中国最大的互联网综合服务提供商之一,也是中国服务用户最多的互联网企业之 。腾讯控股有限公司是一家民营IT企业,由马化腾、许晨晔、曾李青、陈一丹、张志东五位创始人共同创立。总部位于中国广东深圳,于2004年6月16日在香港交易所上市。公司在开曼群岛注册,董事会主席兼首席执行官为马化腾,公司总裁为刘炽平。拥有门户网站腾讯网等。(2) 中国电信(0728.HK、601728.SH):中国电信股份有限公司是一家全球大型的领先的全业务综合智能信息服务运营商,主要在中国提供固定及移动通信服务、互联网接入服务、信息服务,以及其他增值电信服务。于2020年底,本公司拥有约3.51亿移动用户、约1.59亿有线宽带用户及约1.08亿固定电话用户。本公司发行的H股及A股分别在香港联合交易所有限公司和上海证券交易所主板挂牌上市。(3) 金山软件(3888.HK)金山软件是一家于香港联交所上市的中国领先的软件及互联网服务公司,旗下拥有金山WPS、西山居、金山云三家子公司。公司在全球范围内拥有约7,000名员工,并在北京、珠海、成都、大连、广州、武汉及香港等多地分设研发中心,在北美、欧洲、日本及马来西亚等海外市场享有重要的市场份额。3.5 全球重要竞争者表 全球重要竞争者资料来源:资产信息网 千际投行(1) 元平台公司Meta Platforms(NASDAQ:MVRS)元平台公司Meta Platforms,Inc.成立于2004年,前称脸书公司(脸谱公司)Facebook,Inc.(原NASDAQ:FB),总部位于美国加州门洛帕克,全职雇员68,177人,创始人&CEO扎克伯格,是全球最大的社交网络网站。(2) 爱立信(NASDAQ:ERIC)爱立信于1876年由 Lars Magnus Ericsson 创立,总部位于瑞典的Kista。公司为移动和固定网络运营商提供电信设备和相关服务。它通过以下几个部分运作:网络、数字服务、管理服务、新兴业务和其他。网络部门支持所有无线接入技术,并为无线接入和传输提供硬件、软件和相关服务。数字服务部门提供数字业务支持系统、运营支持系统、通信、云核心和云基础设施等领域的软件和服务。管理服务部门包括网络和信息技术管理服务、网络设计和优化、应用程序开发和维护。新兴业务和其他部门包括新兴业务,lconectiv,红蜜蜂媒体,和媒体解决方案。(3) 谷歌(NASDAQ:GOOGL)Alphabet Inc.(原谷歌公司,Google,Inc.)创立于1998年,总部位于美国加州山景城,全职雇员144,056人,是美国乃至全球科技行业龙头,是全球最大的搜索引擎公司、全球排名第二的机器人公司(已售)、Android系统开发商、全球无人驾驶技术及虚拟现实技术领导者、量子计算机开发公司等。Alphabet旗下还拥有重量级投资机构,包括成长资本投资基金CapitalG,以及Alphabet的风险投资公司GV。第四章 未来行业展望中国互联网信息中心指出,“十三五”期间,我国在以互联网为代表的信息通信技术各相关领域均取得前所未有的历史性成就,互联网基础设施建设全面覆盖,互联网普惠深入推进,数字经济欣欣向荣,高新技术加快探索,互联网治理逐步完善。我国人工智能、物联网、区块链等高新科技与互联网相关产业加速结合,推动产业提质增效。4.1 成果回顾一是消费领域应用逐步普及。随着5G、物联网等技术的深入发展,智能设备、智能家居等智能产品迅速普及。2019年,我国智能音箱市场出货量达到4589万台,同比增长109.7%186。二是生产领域应用全面落地。在5G、人工智能等技术的支持下,生产领域的智能化水平已显著提升,一批数字化车间和智能工厂初步建成。2019年,产业数字化增加值规模达28.8万亿元,同比名义增长16.8%,全国开展网络化协同、服务型制造和个性化定制的企业比例分别达到35.3%、25.3%和8.1%187。三是流通领域应用逐渐开展。随着区块链等技术的不断成熟,相关技术在流通领域的应用开始探索实践。2018年,全国首张区块链电子发票在深圳亮相;2020年,我国北京、苏州、深圳等多地已开展数字货币试点工作。4.2 发展方向未来互联网发展有以下几个方向:1. 基础设施建设全覆盖2. 互联网普惠深入推进3. 数字经济欣欣向荣4. 高新科技加快探索5. 网络治理逐步完善
拖不得了,Android11真的来了,最全适配实践指南奉上(上)
前言没错!Android 11(version 30,Andorid R) 正式发布了!看到这个新闻我知道我不能再拖了,再不好好准备好迎接Android11的到来,到时候迎接我的就是客户的指责,甚至老板的一封休书了 😂。今天就和大家一起看看Android11到底改了些什么,以及最重要的,我们需要怎么适配?targetversion不改到30,是不是就不用适配了呢?以下我分为两部分讲述,分别是以Android11 为目标版本的应用(targetSdkVersion>=30才有影响)⭐所有应用在Android11设备上适配改动(无论targetSdkVersion是多少,只要在Android11设备上运行的应用都有影响)为什么先说targetSdkVersion>=30的模块呢?因为一般来说为了Google为了让我们更长时间适应新的内容以及保障线上应用的稳定,都会把改动大的,需要花时间适配的内容放到新的targetSdkVersion对应的应用上,如果你暂时没有适配targetSdkVersion30的需求,也可以看看第二模块,看看是否有涉及你的应用相关内容。GOGOGO!Tips:此适配文章会不间断更新,根据Android11发布进度调整,欢迎点赞关注。(打⭐的格外注意哦)适配targetSdkVersion30此模块的修改内容只针对targetSdkVersion 30或者以上才生效。分区存储强制执行⭐“对外部存储目录的访问仅限于应用专属目录,以及应用已创建的特定类型的媒体。”关于分区存储,在Android10就已经推行了,简单的说,就是应用对于文件的读写只能在沙盒环境,也就是属于自己应用的目录里面读写。其他媒体文件可以通过MediaStore进行访问。但是在android10的时候,Google还是为开发者考虑,留了一手。在targetSdkVersion = 29应用中,设置android:requestLegacyExternalStorage="true",就可以不启动分区存储,让以前的文件读取正常使用。但是targetSdkVersion = 30中不行了,强制开启分区存储。当然,作为人性化的android,还是为开发者留了一小手,如果是覆盖安装呢,可以增加android:preserveLegacyExternalStorage="true",暂时关闭分区存储,好让开发者完成数据迁移的工作。为什么是暂时呢?因为只要卸载重装,就会失效了。以下是关于分区存储会遇到的所有情况,给大家罗列出来了,先上代码:fun saveFile() {
if (checkPermission()) {
//getExternalStoragePublicDirectory被弃用,分区存储开启后就不允许访问了
val filePath = Environment.getExternalStoragePublicDirectory("").toString() + "/test3.txt"
val fw = FileWriter(filePath)
fw.write("hello world")
fw.close()
showToast("文件写入成功")
}
}分情况运行:1) targetSdkVersion = 28,运行后正常读写。2) targetSdkVersion = 29,不删除应用,targetSdkVersion 由28修改到29,覆盖安装,运行后正常读写。3) targetSdkVersion = 29,删除应用,重新运行,读写报错,程序崩溃(open failed: EACCES (Permission denied))4) targetSdkVersion = 29,添加android:requestLegacyExternalStorage="true"(不启用分区存储),读写正常不报错5) targetSdkVersion = 30,不删除应用,targetSdkVersion 由29修改到30,读写报错,程序崩溃(open failed: EACCES (Permission denied))6) targetSdkVersion = 30,不删除应用,targetSdkVersion 由29修改到30,增加android:preserveLegacyExternalStorage="true",读写正常不报错7) targetSdkVersion = 30,删除应用,重新运行,读写报错,程序崩溃(open failed: EACCES (Permission denied))ok,那到底应该怎么改呢?三种方法访问文件:1)应用专属目录//分区存储空间
val file = File(context.filesDir, filename)
//应用专属外部存储空间
val appSpecificExternalDir = File(context.getExternalFilesDir(), filename)2)访问公共媒体目录文件val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc")
if (cursor != null) {
while (cursor.moveToNext()) {
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
println("image uri is $uri")
}
cursor.close()
}SAF(存储访问框架--Storage Access Framework)val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, 100)
@RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
if (requestCode == 100) {
val uri = data.data
println("image uri is $uri")
}
}具体还有很多操作可以看看网上关于分区存储的资料,因为Android10已经出来很久了,所以资料还是很多的,这里推荐几篇访问应用专属文件Android 10适配要点,作用域存储AndroidQ(10)分区存储完美适配说到这里可能又有人问了,那我的应用就是个手机管理器,总不能不让我清其他应用的缓存了吧,有办法!Android提供了两个intent入口:调用ACTION_MANAGE_STORAGE intent 操作检查可用空间。调用ACTION_CLEAR_APP_CACHE intent 操作清除所有缓存。说来说去,反正应用数据私有化是大势所趋,还是早点适配分区存储,别等以后手机只有沙盒机制的时候,就来不及了。媒体文件访问权限 ⭐“为了在保证用户隐私的同时可以更轻松地访问媒体,Android 11 增加了以下功能。执行批量操作和使用直接文件路径和原生库访问文件。”1)执行批量操作这里的批量操作指的是Android 11 向 MediaStore API 中添加了多种方法,用于简化特定媒体文件更改流程(例如在原位置编辑照片),分别是:createWriteRequest() 用户向应用授予对指定媒体文件组的写入访问权限的请求。createFavoriteRequest()用户将设备上指定的媒体文件标记为“收藏”的请求。对该文件具有读取访问权限的任何应用都可以看到用户已将该文件标记为“收藏”。createTrashRequest() 用户将指定的媒体文件放入设备垃圾箱的请求。垃圾箱中的内容会在系统定义的时间段后被永久删除。createDeleteRequest() 用户立即永久删除指定的媒体文件(而不是先将其放入垃圾箱)的请求。直接看个例子:val urisToModify = listOf(uri,uri,...)
val editPendingIntent = MediaStore.createWriteRequest(contentResolver,
urisToModify)
// Launch a system prompt requesting user permission for the operation.
startIntentSenderForResult(editPendingIntent.intentSender, EDIT_REQUEST_CODE,
null, 0, 0, 0)
override fun onActivityResult(requestCode: Int, resultCode: Int,
data: Intent?) {
when (requestCode) {
EDIT_REQUEST_CODE ->
if (resultCode == Activity.RESULT_OK) {
/* Edit request granted; proceed. */
} else {
/* Edit request not granted; explain to the user. */
}
}
}传入uri的集合,获取用户的同意后,就可以进行操作了。2)直接文件路径和原生库访问文件没错!Android11又恢复了使用直接文件路径访问访问媒体文件!哈哈,这样就方便多了。也就是除了 MediaStore API之外还有两种方式可以访问媒体文件:File API。原生库,例如 fopen()。那Android10咋办呢??要不就用MediaStore,要不就直接把分区存储关了吧(requestLegacyExternalStorage=true)所有文件访问权限 ⭐虽然说了这么多,但是还有些应用就要访问所有文件,比如杀毒软件,文件管理器。放心,有办法!MANAGE_EXTERNAL_STORAGE 这不来了吗。这个权限就是用来获取所有文件的管理权限。🌰:<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
val intent = Intent()
intent.action= Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivity(intent)
//判断是否获取MANAGE_EXTERNAL_STORAGE权限:
val isHasStoragePermission= Environment.isExternalStorageManager()来张截图过过瘾:电话号码相关权限 ⭐“Android 11 更改了您的应用在读取电话号码时使用的与电话相关的权限。”具体改了什么呢?其实就是两个API:TelecomManager 类中的 getLine1Number() 方法TelecomManager 类中的 getMsisdn() 方法也就是当用到这两个API的时候,原来的READ_PHONE_STATE权限不管用了,需要READ_PHONE_NUMBERS权限才行。下面具体说说,targetSdkVersion修改到30,然后运行一个获取电话号码的程序:ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_PHONE_STATE), 100)
btn2.setOnClickListener {
val tm = this.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val phoneNumber = tm.line1Number
showToast(phoneNumber)
}崩溃了:java.lang.SecurityException: getLine1NumberForDisplay: Neither user 10151 nor current process has android.permission.READ_PHONE_STATE, android.permission.READ_SMS, or android.permission.READ_PHONE_NUMBERS预想之中哈,Andmanifest.xml中注册好权限,并且添加动态权限申请:<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_PHONE_NUMBERS), 100)搞定,如果你只需要获取手机号码这一个功能,也可以只申请READ_PHONE_NUMBERS这一个权限:<uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />自定义消息框视图被屏蔽 ⭐“从 Android 11 开始,已弃用自定义消息框视图。如果您的应用以 Android 11 为目标平台,包含自定义视图的消息框在从后台发布时会被屏蔽”可能有人会奇怪了,什么是自定义消息框视图啊?我说英文你就知道了,英文是custom toast views,也就是自定义toast。简单写个代码:Toast toast = new Toast(context);
toast.setDuration(show_length);
toast.setView(view);
toast.show();糟了糟了,自定义toast被弃用了?我们项目就是用的这个啊!不用担心,只是不允许自定义toast从后台显示了。比如我写一个3秒后再显示toast,然后应用一打开就进入后台,看看会发生什么:Handler().postDelayed({
IToast.show("你好,我是自定义toast")
}, 3000)
W/NotificationService: Blocking custom toast from package com.example.studynote due to package not in the foreground啥也没显示,只是发出来一个警告。所以不用太过担心,如果实在需要后台显示,就用普通的toast吧!现在需要 APK 签名方案 v2 ⭐“对于以 Android 11(API 级别 30)为目标平台,且目前仅使用 APK 签名方案 v1 签名的应用,现在还必须使用 APK 签名方案 v2 或更高版本进行签名。用户无法在搭载 Android 11 的设备上安装或更新仅通过 APK 签名方案 v1 签名的应用。”这个介绍已经很明显了吧,如果你的targetSdkVersion修改到30,那么你就必须要加上v2签名才行。否则无法安装和更新。媒体intent操作需要系统默认相机 ⭐从 Android 11 开始,只有预装的系统相机应用可以响应以下 intent 操作:android.media.action.VIDEO_CAPTUREandroid.media.action.IMAGE_CAPTUREandroid.media.action.IMAGE_CAPTURE_SECURE也就是说,如果我调用intent唤起照相机,使用VIDEO_CAPTURE的action,只有系统的相机能够响应,而第三方的相机应用不会响应了。val intent=Intent()
intent.action=android.provider.MediaStore.ACTION_IMAGE_CAPTURE
startActivity(intent)
//无法唤起第三方相机了,只能唤起系统相机这点对普通的相机应用还是有点打击的,官方给的建议是如果要使用特定的第三方相机应用来代表其捕获图片或视频,可以通过为intent设置软件包名称或组件来使这些intent变得明确。5G ⭐“Android 11 添加了在您的应用中支持 5G 的功能”新的Android11也是支持了5G相关的一些功能,包括:检测是否连接到了5G网络检查按流量计费性首先是检测5G网络,通过TelephonyManager的监听方法:private fun getNetworkType(){
val tManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
tManager.listen(object : PhoneStateListener() {
@RequiresApi(Build.VERSION_CODES.R)
override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
if (ActivityCompat.checkSelfPermission(this@Android11Test2Activity, android.Manifest.permission.READ_PHONE_STATE) != android.content.pm.PackageManager.PERMISSION_GRANTED) {
return
}
super.onDisplayInfoChanged(telephonyDisplayInfo)
when(telephonyDisplayInfo.networkType) {
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> showToast("高级专业版 LTE (5Ge)")
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> showToast("NR (5G) - 5G Sub-6 网络")
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> showToast("5G+/5G UW - 5G mmWave 网络")
else -> showToast("other")
}
}
}, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
}如果是5g网络,就免不了要去判断是不是按流量计费的,否则5G的流量可不是开玩笑的。检测流量计费方法也很简单,监听网络,在回调中判断:val manager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
manager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)
//true 代表连接不按流量计费
val isNotFlowPay=networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) ||
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
}
})判断该值,如果为 true,则将连接视为不按流量计费。后台位置信息访问权限 ⭐“在搭载 Android 11 的设备上,当应用中的某项功能请求在后台访问位置信息时,用户看到的系统对话框不再包含用于启用后台位置信息访问权限的按钮。如需启用后台位置信息访问权限,用户必须在设置页面上针对应用的位置权限设置一律允许选项。”什么意思呢?主要涉及到两点:从Android10系统的设备开始,就需要请求后台位置权限(ACCESS_BACKGROUND_LOCATION),并选择Allow all the time (始终允许)才能获得后台位置权限。Android11设备上再次加强对后台权限的管理,主要表现在系统对话框上,对话框不再提示始终允许字样,而是提供了位置权限的设置入口,需要在设置页面选择始终允许才能获得后台位置权限。在搭载Android11系统的设备上,targetVersion小于11的时候,可以前台后台位置权限一起申请,并且对话框提供了文字说明,表示需要随时获取用户位置信息,进入设置选择始终允许即可。但是targetVersion为30的时候,你必须单独申请后台位置权限,而且要在获取前台权限之后,顺序不能乱。并且无任何提示,需要开发者自己设计提示样式。可能有点绕,操作几个例子说明:1)Android10设备,申请前台和后台位置权限(任意targetSdkVersion):requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100)执行效果:2)Android11设备,targetSdkVersion<=29(Android 10),申请前台和后台位置权限:requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100)执行效果:3)Android11设备,targetSdkVersion=30(Android 11),申请前台和后台位置权限:requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100)执行无反应4)Android11设备,targetSdkVersion=30(Android 11),先申请前台位置权限,后申请后台位置权限:requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 100)执行效果:requestPermissions(arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100)执行效果(直接跳转到设置页面,无任何说明):所以,该怎么适配呢?targetSdkVersion<30情况下,如果你之前就有判断过前台和后台位置权限,那就无需担心,没有什么需要适配。targetSdkVersion>30情况下,需要分开申请前后台位置权限,并且对后台位置权限申请做好说明和引导,当然也是为了更好的服务用户。权限申请的demo代码:val permissionAccessCoarseLocationApproved = ActivityCompat
.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
if (permissionAccessCoarseLocationApproved) {
val backgroundLocationPermissionApproved = ActivityCompat
.checkSelfPermission(this, permission.ACCESS_BACKGROUND_LOCATION) ==
PackageManager.PERMISSION_GRANTED
if (backgroundLocationPermissionApproved) {
//前后台位置权限都有
} else {
//申请后台权限
if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R){
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
200)
}else{
AlertDialog.Builder(this).setMessage("需要提供后台位置权限,请在设置页面选择始终允许")
.setPositiveButton("确定", DialogInterface.OnClickListener { dialog, which ->
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
200)
}).create().show()
}
}
} else {
if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.R){
//申请前台和后台位置权限
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_BACKGROUND_LOCATION),
100)
}else{
//申请前台位置权限
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
100)
}
}软件包可见性 ⭐“Android 11 更改了应用查询用户已在设备上安装的其他应用以及与之交互的方式。使用新的元素,应用可以定义一组自身可访问的其他应用。通过告知系统应向您的应用显示哪些其他应用,此元素有助于鼓励最小权限原则。此外,此元素还可帮助 Google Play 等应用商店评估应用为用户提供的隐私权和安全性。”也就是说,Android11中,如果你想去获取其他应用的信息,比如包名,名称等等,不能直接获取了,必须在清单文件中添加<queries>元素,告知系统你要获取哪些应用信息或者哪一类应用。比如我这段查询应用信息的代码:val pm = this.packageManager
val listAppcations: List<ApplicationInfo> = pm
.getInstalledApplications(PackageManager.GET_META_DATA)
for (app in listAppcations) {
Log.e("lz",app.packageName)
}在Android11版本,只能查询到自己应用和系统应用的信息,查不到其他应用的信息了。怎么呢?添加<queries>元素,两种方式:1)元素中加入具体包名<manifest package="com.example.game">
<queries>
<package android:name="com.example.store" />
<package android:name="com.example.services" />
</queries>
...
</manifest>2)元素中加入固定过滤的intent<manifest package="com.example.game">
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/jpeg" />
</intent>
</queries>
</manifest>可能还是有人会疑惑,那我的应用是浏览器或者设备管理器咋办呢?我就要获取所有包名啊?放心,Android11还引入了 QUERY_ALL_PACKAGES 权限,清单文件中加入即可。但是Google Play可不一定能滥用哦,它为需要QUERY_ALL_PACKAGES 权限的应用会提供相关指南,但是还没出来,具体要看后面的消息了。至于国内市场。。。(希望能有个应用市场一统天下好好管理这混乱的市场吧!)文档访问限制“为让开发者有时间进行测试,以下与存储访问框架 (SAF) 相关的变更只有在应用以 Android 11 为目标平台时才会生效。”上文存储的时候说过可以通过SAF(存储访问框架--Storage Access Framework)来访问公共目录,但是Android11再次升级,部分目录和文件不能访问了,具体如下:无法再使用 ACTION_OPEN_DOCUMENT_TREE intent 操作请求访问以下目录:内部存储卷的根目录。设备制造商认为可靠的各个 SD 卡卷的根目录,无论该卡是模拟卡还是可移除的卡。可靠的卷是指应用在大多数情况下可以成功访问的卷。Download 目录。无法再使用 ACTION_OPEN_DOCUMENT_TREE 或 ACTION_OPEN_DOCUMENT intent 操作请求用户从以下目录中选择单独的文件:Android/data/ 目录及其所有子目录。Android/obb/ 目录及其所有子目录。限制对 APN 数据库的读取访问“以 Android 11 为目标平台的应用现在必须具备 Manifest.permission.WRITE_APN_SETTINGS 特权,才能读取或访问电话提供程序 APN 数据库。如果在不具备此权限的情况下尝试访问 APN 数据库,会生成安全异常。”问题来了,APN是啥?指一种网络接入技术,是通过手机上网时必须配置的一个参数,APN配置参数包括名字,运营商编号,APN接入点等等。就是说如果没有Manifest.permission.WRITE_APN_SETTINGS权限就不能读取APN数据库了,但是!这个权限很早之前就被限定只有系统程序才能申请这个权限了,现在这个特权没理解到是什么意思,难道系统程序都不能随便申请了?有大神可以评论区留言告知。在元数据文件中声明“无障碍”按钮使用情况“从 Android 11 开始,您的无障碍服务无法在运行时声明与系统的“无障碍”按钮的关联。如果您将 AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON 附加到 AccessibilityServiceInfo 对象的 flags 属性,框架就不会将“无障碍”按钮回调事件传递给您的服务。”做过无障碍辅助功能的应该都知道AccessibilityServiceInfo要设置flag为FLAG_REQUEST_ACCESSIBILITY_BUTTON,getAccessibilityButtonController方法获取辅助功能按钮控制器,并且可用于查询辅助功能按钮的状态并注册监听器以进行交互和辅助功能按钮的状态更改。但是,Android 11开始,这样写不能获取辅助按钮回调事件了,得换成另外一种写法。在元数据文件(通常为 res/raw/accessibilityservice.xml)中使用 flagRequestAccessibilityButton 标记声明您的无障碍服务与“无障碍”按钮的关联。Firebase JobDispatcher 和 GCMNetworkManager“如果您的应用以 API 级别 30 或更高级别为目标平台,在搭载 Android 6.0(API 级别 23)或更高版本的设备上会停用 Firebase JobDispatcher 和 GcmNetworkManager API 调用。”这两个api国内都用不了,主要用于后台任务。官方给出的替代意见是WorkManager,这个国内是可以用的,属于jetpack组件,主要用于调度和执行可延期的后台工作。设备到设备文件传输“如果您的应用以 Android 11 为目标平台,您将无法再使用 allowBackup 属性停用应用文件的设备到设备迁移。系统会自动启用此功能。不过,即使您的应用以 Android 11 为目标平台,您也可以通过将 allowBackup 属性设置为 false 来停用应用文件的云端备份和恢复。”android:allowBackup属性代表是否允许应用参与备份和恢复基础架构。如果将此属性设为 false,则永远不会为该应用执行备份或恢复,即使是采用全系统备份方法也不例外(这种备份方法通常会通过 adb 保存所有应用数据)。此属性的默认值为 true。所以这里是不能停用文件的设备到设备迁移,但是可以停用云端备份和恢复自动重置权限“如果应用以 Android 11 为目标平台并且数月未使用,系统会通过自动重置用户已授予应用的运行时敏感权限来保护用户数据。此操作与用户在系统设置中查看权限并将应用的访问权限级别更改为拒绝的做法效果一样。如果应用已遵循有关在运行时请求权限的最佳做法,那么您不必对应用进行任何更改。这是因为,当用户与应用中的功能互动时,您应该会验证相关功能是否具有所需权限。”官方说明说的很清楚了,而且只要应用遵循有关在运行时请求权限的最佳做法,也就是每次需要调用权限的时候都会去判断,那么就不会有什么问题。如果需要关闭这个功能怎么办呢?只有引导用户去设置页面关闭了,可以调用包含Settings.ACTION_APPLICATION_DETAILS_SETTINGS action的 Intent将用户定向到系统设置中应用的页面。怎么检查应用是否停用自动重置功能呢?调用 PackageManager的isAutoRevokeWhitelisted()方法。如果此方法返回 true,代表系统不会自动重置应用的权限。前台服务类型“从 Android 9 开始,应用仅限于在前台访问摄像头和麦克风。为了进一步保护用户,Android 11 更改了前台服务访问摄像头和麦克风相关数据的方式。如果您的应用以 Android 11 为目标平台并且在某项前台服务中访问这些类型的数据,您需要在该前台服务的声明的 foregroundServiceType 属性中添加新的 camera 和 microphone 类型。”举例,如果应用某项前台服务需要访问位置信息、摄像头和麦克风,那么就这样添加:<manifest>
<service ...
android:foregroundServiceType="location|camera|microphone" />
</manifest>
1分钟 Serverless极速搭建高性能网盘-5
个人网盘的成本计算日常应用网盘您除了会关注功能,一定会关注费用问题,这一部分会对这个网盘的费用进行比较详细的剖析,给需要长期使用本网盘的同学。成本剖析计算费用: 0.000110592元/GB-秒, 每个月有 40万 GB-秒的免费额度,这项基本免费。流量费用:函数请求响应流量:0.50元/GB, 取决于您每个月从您的网盘上下载文件的多少, 上传没有流量费用。上传和下载均没有限速。持久化费用:使用阿里云 NAS, 主要部署 kodbox 应用需要的 sqlite 数据库, 0.35(*结合低频介质,低至0.19) GB/月, 由于 NAS 单价比较贵, 建议 NAS 盘只做 kodbox 的 sqlite 数据库存储, 不会超过1G, 费用即 0.35 元。在单纯存储这块, 可以选择您自己存储类型,以使用 OSS 做文件存储为例, OSS 存储价格如下表, 如果电影收集爱好者, 大部分电影应该是冷归档型,假设有 100GB 的存储资源,那么每个月的存储费用是 1.5 元。以小明的网盘为具体示例小明使用这个方案做自己的私有或家庭网盘,目前大约有 150G 的资源存储通过对 OSS 结合基于最后一次修改时间的生命周期规则实现Bucket内指定前缀的Object在达到指定天数后转换为目标存储类型,策略说明如下:Object存储30天后,自动转换为低频访问类型。Object存储180天后,自动转换为归档存储类型。Object存储360天后,自动转换为冷归档存储类型。假设小明的资源的分布情况如下:最新的存储资源(30 天以内), 5G30-180天内的资源, 20G180天-360天的资源,25G超过360天的资源,100GNAS 作为数据库: 0.35 元因此小明每个月的存储费用为: 0.12 * 5 + 20 * 0.08 + 25 * 0.033 + 100 * 0.015 + 0.35 = 4.875计算函数计算 0.000110592元/GB-秒, 每个月都有 40万 GB-秒的免费额度(这个等价于 1核(1.5G) 的机器完整执行 74.1 小时), 函数计算是按毫秒计费的, 每次操作, 只是相当执行一次函数调用, 比如预览, 看起来您预览这个文章花费了很长时间, 实际上的耗费, 就是预览那次请求,后端执行的是100-200s 的时间(即计费也在这个时间), 按照网盘的操作频率, 这项应该基本在免费额度内。流出流量该方案最大的优势就是上传和下载没有任何限速, 上传没有流量费用。 理论上 FC 一个实例, 最大内网带宽是1Gbps, 最大外网带宽是 100Mbps。假设小明每个月, 会翻阅自己网盘内的电影和照片, 假设每个月消耗的流量是 15G, 流量费用为 0.5 * 15 = 7.5总结小明一个月的总费用为: 4.875 + 7.5 = 12.375 元
美团面试官问我: ZGC 的 Z 是什么意思(上)
本文的阅读有一定的门槛,请先了解 GC 的基本只知识。现代垃圾收集器的演进大部分都是往减少停顿方向发展。像 CMS 就是分离出一些阶段使得应用线程可以和垃圾回收线程并发,当然还有利用回收线程的并行来减少停顿的时间。基本上 STW 阶段都是利用多线程并行来减少停顿时间,而并发阶段不会有太多的回收线程工作,这是为了不和应用线程争抢 CPU,反正都并发了慢就慢点(不过还是得考虑内存分配速率)。而 G1 可以认为是打开了另一个方向的大门:只回收部分垃圾来减少停顿时间。不过为了达到只回收部分 reigon,每个 region 都需要 RememberSet 来记录各 region 之间的引用。这个内存的开销其实还是挺大的,可能会占据整堆的20%或以上。并且 G1 还有写屏障的开销,虽说用了 logging wtire barrier,但也还是有开销的。当然 CMS 也用了写屏障,不过逻辑比较简单,啥都没判断就单纯的记录。其实 G1 相对于 CMS 只有在大堆的场景下才有优势,CMS 比较伤的是 remark 阶段,如果堆太大需要扫描的东西太多。而 G1 在大堆的时候可以选择部分收集,所以停顿时间有优势。今天的主角 ZGC 和 G1 一样是基于 reigon 的,几乎所有阶段都是并发的,整堆扫描,部分收集。而且 ZGC 还不分代,就是没分新生代和老年代。那它为啥比 G1 要牛皮?今天咱们就来盘一盘。本文会先介绍 ZGC 的特性,或者说几个关键点,然后再简述下整体回收流程。基本上看下来对 ZCG 心中就有数了,作为普通的 Javaer,了解到这个程度就差不多了。好了,让我们进入今天的正题!ZGC 的目标垃圾收集器设计出来都有目标的,有些是为了更高的吞吐,有些是为了更低的延迟。关键字:并发、基于Region、整理内存、支持NUMA、用了染色指针、用了读屏障,对了 ZGC 用的是 STAB。Concurrent这个 Concurrent 的意思是和应用线程并发执行,ZGC 一共分了 10 个阶段,只有 3 个很短暂的阶段是 STW 的。所以我们先看看 ZGC 的目标:可以看到只有初始标记、再标记、初始转移阶段是 STW 的。初始标记就扫描 GC Roots 直接可达的,耗时很短,重新标记一般而言也很短,如果超过 1ms 会再次进入并发标记阶段再来一遍,所以影响不大。初始转移阶段也是扫描 GC Roots 也很短,所以可以认为 ZGC 几乎是并发的。而且之所以说停顿时间不会随着堆的大小和存活对象的数量增加而增加,是因为 STW 几乎只和 GC Roots 集合大小有关,和堆大小没啥关系。这其实就是 ZGC 超过 G1 很关键的一个地方, G1 的对象转移需要 STW 所以堆大需要转移对象多,停顿的时间就长了,而 ZGC 有并发转移。不过并发回收有个情况就是回收的时候应用线程还是在产生新的对象,所以需要预留一些空间给并发时候生成的新对象。如果对象分配过快导致内存不够,在 CMS 中是发生 Full gc,而 ZGC 则是阻塞应用线程。所以要注意 ZGC 触发的时间。ZGC 有自适应算法来触发也有固定时间触发,所以可以根据实际场景来修改 ZGC 触发时间,防止过晚触发而内存分配过快导致线程阻塞。还有设置 ParallelGCThreads 和 ConcGCThreads,分别是 STW 并行时候的线程数和并发阶段的线程数来加快回收的速度。不过 ConcGCThreads 数量需要注意,因为此阶段是和应用线程并发,如果线程数过多会影响应用线程。其实 ZGC 的每个阶段都是串行的,所以理论上其实可以不需要分两类线程,那为什么分了这两类线程?就是为了灵活设置。分成两类就可以通过配置来调优,达到性能最大值。对了上面提到 ZGC 的 STW 和 GC Roots 集合大小有关系,所以如果在会生成很多线程、动态加载很多 ClassLoader 等情况下会增加 ZGC 的停顿时间。这点需要注意。Region-based为了能更细粒度的控制内存的分配,和 G1 一样 ZGC 也将堆划分成很多分区。分了三种:2MB、32MB 和 X*MB(受操作系统控制)。下图为源码中的注释:对于回收的策略是优先收集小区,中、大区尽量不回收。Compacting和 G1 一样都分区了所以肯定从整体来看像是标记-复制算法,所以也是会整理的。因此 ZGC 也不会产生内存碎片。具体的流程下文再做分析。NUMA-aware以前的 G1 是不支持的,不过在 JDK14 G1 也支持了。可能有的同学对 NUMA 不太熟悉,没事我先来解释一波。在早期处理器都是单核的,因为根据摩尔定律,处理器的性能每隔一段时间就可以成指数型增长。而近年来这个增长的速度逐渐变缓,于是很多厂商就推出了双核多核的计算机。早期 CPU 通过前端总线到北桥到内存总线然后才访问到内存。这个架构被称为 SMP (Symmetric Multi-Processor),因为任一个 CPU 对内存的访问速度是一致的,不用考虑不同内存地址之间的差异,所以也称一致内存访问(Uniform Memory Access, UMA )。这个核心越加越多,渐渐的总线和北桥就成为瓶颈,那不能够啊,于是就想了个办法。把 CPU 和内存集成到一个单元上,这个就是非一致内存访问 (Non-Uniform Memory Access,NUMA)。但是因为内存被切分为本地内存和远程内存,当某个模块比较“热”的时候,就可能产生本地内存爆满,而远程内存都很空闲的情况。比如 64G 内存一分为二,模块一的内存用了31G,而另一个模块的内存用了5G,且模块一只能用本地内存,这就产生了内存不平衡问题。如果有些策略规定不能访问远程内存的时候,就会出现明明还有很多内存却产生 SWAP(将部分内存置换到硬盘中) 的情况。即使允许访问远程内存那也比本地内存访问速率相差较大,这是使用 NUMA 需要考虑的问题。ZGC 对 NUMA 的支持是小分区分配时会优先从本地内存分配,如果本地内存不足则从远程内存分配。对于中、大分区的话就交由操作系统决定。上述做法的原因是生成的绝大部分都是小分区对象,因此优先本地分配速度较快,而且也不易造成内存不平衡的情况。而中、大分区对象较大,如果都从本地分配则可能会导致内存不平衡的情况。
对话汇量科技副总裁奚原:如果把先进算法比喻成矛,那稳定的平台与算力便是配套的盾
国内企业投身“大航海时代”其实早在很多年前,在世界各地的旅游区或商场里,Made in China 的商品随处可见。从玩具、箱包、五金到饰品,甚至到风靡全球的老干妈辣酱,这些商品让在海外的国人倍感亲切。最近几年,移动互联网企业出海浪潮浩浩荡荡,不仅 BAT、字节跳动、华为、猎豹等互联网科技公司雄心勃勃地大手笔布局海外市场,更有不少创业公司投身“大航海时代”。小米、OPPO 等智能手机品牌在海外圈粉无数,多款中国游戏风靡海外。抖音、快手相继在海外推出 TikTok、Kwai、Zynn 等短视频平台,以期在短视频风口抢占全球流量入口。此外,一些国内不那么为人所知的品牌,已经在海外打下了自己的半壁江山,比如“非洲的手机之王”传音,比如成立仅 6 年就在拉美和中东拥有 2 亿短视频用户的中国初创公司大宇无限等等。这些案例只是中国企业出海的沧海一粟。今年 3 月,我国贸促会研究院的报告显示,中国对外直接投资的流量和存量连续四年稳居全球前三名。报告还显示,近八成的中国企业将会维持和扩大对外投资的意向,看好对外投资前景。同时,值得注意的是,在 2021 年世界财富五百强中有 143 家中国企业上榜,2020 年这个数字是 133 家,仅一年就增加了 10 家。可以说中国企业的出海始终处在一个“快车道”上。在数字技术的推动下,越来越多的中国企业正在加快海外业务扩张的脚步,他们“走出去”的道路也越来越宽广。我国数字经济出海六大趋势在这样的大背景下,我国与数字经济相关的出海正从“数字化出海”向“出海数字化”扩展,从早期的互联网社交、视频和短视频、互联网工具等在内的数字化产业的出海,逐步带动传统行业的出海企业积极借助数字化技术,进行出海业务的全方位数字化转型和创新,在海外实现产品升级和品牌升级,提升全球竞争力。从欧美到非洲,中国企业出海遍地开花。目前,60%的出海企业海外业务已经涉及三个以上大洲/地区。东南亚、欧洲和北美依然占据中国企业出海的首选目的地,同时,南美、非洲、中东等新兴地区正成为中国企业出海的“新蓝海”。除了中国企业在全球遍地开花这一重要趋势外,另外五大中企出海趋势也愈发凸显:从“制”到“智”,出海力量再升级。中国企业出海正在经历从劳动密集型、资本密集型的产品出口到技术驱动型、思维创新型、品牌先导型的升级之路,实现从量到质的转变;从向全球输出“中国成本”、“中国规模”,转而向全球输出“中国技术”、“中国品牌”和“中国体验”。从传统到新势力,新能源车开辟出海新赛道。随着电动化浪潮席卷全球汽车行业,无论传统车企还是以新能源汽车为代表的造车新势力,都在积极布局海外,希望实现弯道超车。从 to C 到 to B,企业服务领域成出海新热点。从企业资源规划、客户关系管理 、协同办公 、人力资源等通用型企业级服务,到垂直行业所需的具体服务,再到 IT 运维管理、数据库及大数据分析等 IT 应用,企业服务领域正在成为出海的新热点。甚至部分原来面向 C 端的出海企业,也把自身服务 C 端客户的经验开发成服务 B 端的新服务,向 B 端拓展业务。从“大”到“小”,中小企业出海崭露头角。已经出海的企业中,大企业占 63%,中小企业占 37%;计划出海的企业中,大企业占 35%,中小企业占 65%,中小企业表现出强烈的出海意愿。从萌芽到成长,初创企业出道即瞄准出海。从游戏、开发者服务和 SaaS,到硬件/手机、电商等行业,越来越多的初创企业是生而全球化的。2021 年埃森哲中国独角兽研究显示,45%的独角兽企业认为海外拓展至关重要,其中,82%的企业计划 24 个月内就进军海外。去年 7 月,国家三部委联合发文,鼓励中国企业积极融入数字经济全球产业链,无疑,数字经济迎来了更好的机遇。然而,这些企业的出海之路也并非一帆风顺。2020 年,TikTok 受到美国政府打压,加之新冠肺炎疫情蔓延全球、国际贸易摩擦加剧,中国互联网企业出海面临着诸多风险与挑战。安全合规是本地化运营的 Job Zero今天,全球安全合规的环境日益复杂,全球已经有 130 多个国家和地区制定了数据保护和隐私相关的法律法规。在出海企业面临的诸多挑战中,首当其冲的是要解决安全和合规问题。随着企业业务拓展,越来越多的企业去到了全球不同区域、甚至一家企业还会在不同的行业赛道开展业务,使得他们要同时满足不同地区、不同行业的合规要求。具体来说,企业需要能够支撑海外业务拓展的安全合规的基础设施,满足不同地区的具体合规要求,以及具备保护数据安全、抵御安全风险的能力。对出海企业来说,安全和合规是企业本地化运营的“Job Zero”。对于汇量科技(Mobvista)这样一家为出海企业提供广告和营销科技产品的开发者技术服务平台来说更是如此。据汇量科技副总裁奚原介绍,“汇量科技非常注重用户数据资产的保护,集团在 17 年起已开始了对旗下业务板块进行多项合规认证。从短期效益来看,花费大量时间成本在短期难以看出成效的数据安全、隐私保护上,似乎有种‘吃力不讨好’的意味。但实际上,我们在合规安全上的超前一步,就是为业务发展提供了重要支撑:一个是全球市场的快速扩张,另一个则是在‘SaaS 工具生态’的构建上。云计算、AI、5G 等技术的应用,让生产、服务过程加速数字化、云化。产业数字化转型在创造巨大价值的同时,各行业面临的安全威胁也在增长:由于生产业务数据均储存在 SaaS 厂商的数据库中,数据的安全问题已不同以往。从 2019 年年中起,Mintegral 就开始基于新的哈希体系脱敏用户设备的描述信息,并逐步侧重用户即时兴趣的建模和预估。这是一套完全不同于传统依赖确定性用户信息的建模体系,目前已取得了非常积极的优化效果,预期将在日趋严格的隐私监管环境下帮助广告主和媒介发布商实现持续增长。如果把先进算法比喻成矛,那稳定的平台与算力便是配套的盾。从云商的角度来看,稳定的资源与可信赖的服务对于用户来说会是长期的关键议题。”此外,在使用数据的过程中,汇量使用的也是自己开发的隐私计算技术,其内部称之为‘可用而不可看’。也就是用这类一方或者二方数据,结合三方去优化广告投放效果,但是最终目的不是去获取这些数据,因为这些数据本身对企业来说没有太大的价值,使用这些数据更多地是为了优化广告效果。想要尽可能地优化广告效果,单凭有价值的数据是远不够的。在强化推荐系统方面,汇量科技自主开发了一款智能推荐引擎——MindAlpha,目前已应用到实际业务中。MindAlpha 每天处理的数据量现在已达数十个 PB,使用的模型特征、参数也超过了数百亿,在线的推理量每天是超过 10 万亿次。目前 Mintegral 平台已经具备程序化广告交易链路上每一个环节的全栈能力,每天处理的程序化广告请求在一千亿到两千亿次,而且随着数据的累积不断进行自我的训练和迭代。算法层面,汇量科技很早就布局了在没有 IDFA 情况下的用户的建模,也就是用户兴趣建模算法,区别于现在整个行业的通用的 IDFA 的算法,汇量科技更多是从两个方面来做创新:一方面是基于用户的上下文去实时获取用户的兴趣建模;另一方面为了保障数据隐私,技术上更多地去搭建一个用户簇,不是倚靠一个用户的数据,而是一群用户的共同特征,从而提高广告的精准度。除了要解决好安全合规问题外,从宏观角度来讲,企业出海还会面临不同市场政策、不同法规的影响。选择怎样的媒体渠道投放?怎样根据受众的偏好定制合适的营销素材?用什么工具来提升整体营销的 ROI? 这些都是企业会面临的挑战。针对这些问题,服务了众多出海企业的汇量科技有着一定的话语权。奚原认为,“在增长层面,企业需要基于对不同地区的文化、受众的深刻了解,定制化地优化他们出海的产品、甚至推广路径。面对当下的疫情,很多企业都加大了对线上营销手段的投入,在这个背景下,企业跨区域推广更需要可以快速规模化的增长路径、可以整合多种营销渠道的产品资源来辅助他们进行跨区域推广。对于大部分中小企业或开发者来说,应该更好地去理解云的概念并积极开展云上业务,要尽可能把资源和服务利用好”。采访嘉宾:奚原,汇量科技副总裁。
数字化企业敏捷建模
作为 DDDChina 的发起者之一,看着越来越多的技术人员加入到领域驱动设计(Domain Driven Design,DDD)社区,分享经验、总结实践、甚至于辩论观点,确实十分高兴。然而,担忧的仍然是并未看到很多非技术人员参与其中,当初力推 DDD 的目的仿佛渐行渐远 —— 我们一直认为 DDD 是促进业务和技术在系统架构上逐步达成共同认知的一种好方法。只有共同认知才能共同演进,才有能够避免一次又一次上演的遗留系统惨剧。也许是疫情给了更多独立思考的时间,没有能够吸引更多的非技术专业人员加入,应该说并非是我们声音不够大,更重要是 DDD 所涉及的方法仅仅瞄准了整个企业架构建模过程的一个阶段,对于我们希望吸引的非技术群体,他们有着自己更需要参与并负责的阶段。这促使我开始从整个企业的视角去考虑架构建模问题,目标也不仅仅局限于让系统架构能够跟随业务需求的变化而持续演进。面对这个数字化时代,企业的数字化底座成为了核心基石,而这个底座的架构是高质量可持续发展的关键。我希望去解决当下很多人都已经看到的传统企业架构方法带来的问题,从不同的视角去尝试新的方法,找到破局之路。从静态走向动态“Be water, my friend.” - Bruce Lee(李小龙)随着数字化进程的持续深化,企业越来越依赖于自身的信息化和数字化系统,甚至很多新兴业务的诞生就源自于技术的发展,比如现在大家习以为常的人脸识别认证方式,正是由于机器学习技术在近 5 年的快速突破才得以实现。这样的依赖性一方面激励着企业在信息和数字化系统研发方面持续加大投入,另一方面也让系统的全局复杂度快速攀升。过去从企业内部运营视角出发形成的简单通用信息系统划分,如 ERP、CRM 等,已经完全不能满足数字化时代企业的需要了。于是我们也看到阿里这样的互联网巨头提出了业务强绑定的“中台”系统概念。移动互联给我们展现了数字化业务的潜力,而未来的元宇宙、Web3.0 将有可能带来更多的创新、甚至颠覆性的业务。由此企业所依托的信息化和数字化系统必然会要求很大程度上的“定制化”,这也让针对全局设计的企业架构(Enterprise Architecture,EA)工作变得越来越重要。然而,已有的企业架构方法,如 TOGAF 和 Zachman,更多关注的是企业架构治理的流程和参考内容模型,希望从一个抽象层面指导企业产出适合于当前业务的企业架构全局视图。为了驾驭日益复杂的业务场景,往往需要将设计和实施步骤越来越细化,从而能够调动不同的的专业细分人员来完成固定事项。在企业实际应用过程中,这样的企业架构方法带来了两个比较显著的问题:产出的架构模型及组件划分更多是以确定性的“静态”视图呈现,每个阶段的产出往往是通过特定人群“翻译”上一个阶段模型而得出的,这样的工作模式有违软件需求的基本特征,即需求的澄清实际是通过可工作的软件交付来迭代完成的;对于未来业务的变化和创新“设计”不足,往往只能将感觉变化比较快的领域,如移动互联网应用,划到产出的架构模型之外,美其名曰“非模型”需求。不少企业架构专家提出信息化系统在一些行业的主干业务上应该是比较清晰的,由此,类似 TOGAF 方法的“静态”产出应该是适合的。然而,我们需要看到,这样的假设实则非常危险:在通信行业,从 2G、3G 到 4G 的连续发展,给了大家类似的预期;然而 5G 的到来,很大程度上颠覆了过去十几年积累的系统模块划分,于是全球各大运营商纷纷开始高喊数字化转型,其中很大一部分工作就是要改变过去的信息化系统架构。国内不少大型银行都在实施基于 Zachman 方法的企业架构,希望通过统一的业务模型和 IT 模型来驱动新一代信息化系统建设,从而能够支撑未来的数字化业务发展。然而即使如清算这样看似稳定的底座,真的就已经业务上明确了吗?数字货币和区块链技术应该说才刚刚崭露头角,未来的具体影响还不得而知。我们更应该尊重这个科技时代的客观规律,不能一边高喊着“主动求变”,一边却在为系统的演进设定“确定性”的障碍。这样一时的大力而为,埋下的是未来的诸多隐患,苦的是为了业务连续性而需要持续开发和维护系统的研发团队。由此,我们希望用动态的“建模”,来替代大家习以为常静态的“架构”。我们希望推动一系列针对企业价值定位的、可持续的、可落地的建模活动,来促进整个企业的系统体系得以持续的演进,从而能够通过持续提升组织的整体架构认知,完成对业务发展的支撑和创新的使能。(数字化企业敏捷建模方法高阶视图:三个建模过程域+ 两个运营闭环)针对软件开发本质去建模“[...in interaction diagrams], comprehensiveness is the enemy of comprehensibility.”― Martin Fowler(老马), “UML Distilled: A Brief Guide to the Standard Object Modeling Language”软件带来的新产品形态在这个数字化时代被越来越多的人认知。作为程序员,我们曾经很难向业务同事解释为什么之前加一个按钮一天完成,现在加一个类似按钮需要三天。而现在大家都知道软件从第一行代码开始就是会被持续修改的,是否易于修改成为了开发效率的基础。真正的难点是如何让软件在面对未来源源不断新需求时,持续保持较低的修改成本。这件事情对于一个单体软件已经是非常困难的事情,而在我们的企业架构上下文里,面对的是一个成百上千软件组成的系统,这件事情就更是难上加难。在这样的环境中,我们没有办法预测未来的需求,只能通过持续提升团队对于“好修改”的认知,并落实到大家的日常工作实践中来应对。显然,在过去的企业架构方法中,我们鲜有看到对软件这个本质属性的关注。更像是今朝有酒今朝醉,明日问题归别人的视而不见。在总结这套方法的同时,很欣喜地发现在不同企业架构阶段的建模活动设计上,早有全球专家意识到了过去这些静态架构方法的危害。比如已经提出近 20 年的领域驱动设计(Domain Driven Design,DDD),目前在云原生的微服务时代被很多组织引入,作为系统和平台设计的方法,其精髓就在持续地构建广泛的、跨业务和技术层面的“统一语言”,减少翻译工作,从而能够让系统的架构随着业务的变化快速持续演进。最近两年行业内从“逆康威定律”出发,转换了在服务组件和技术架构设计上的单一视角,从组织和团队划分出发,明确组件设计目标带来的对应团队特征的不同,并能够从持续发展的视角来设计团队的动态划分和演进。这种团队拓扑(Team Topologies)的思想,实际上已经为我们提供了在技术实现层面上的持续建模活动蓝本。(团队拓扑 Team Topologies 知识图谱,来源于《高效能团队模式:支持软件快速交付的组织架构》一书作者总结。)站在这些新思想和方法之上,让我们一起来定义针对数字化企业的建模方法:● 我们认可业务和应用架构的重要性,但更重要的是持续价值建模,任何业务和应用架构只是实现预期商业价值的一种支撑;● 我们认可系统和平台架构的重要性,但更重要的是持续领域建模,任何系统和平台架构只是应对复杂问题分治的一种结果;● 我们认可服务和技术架构的重要性,但更重要的是持续组织建模,任何服务和技术架构只是高效实现组织划分的一种映射(康威定律)。在以上的定义中,业务架构阶段指明确架构所需满足的业务目标的定义过程,由于越来越多的数字原生业务,技术和业务的高度融合造成不少企业直接采用应用的说法。系统架构阶段,或云时代越来越多的平台型架构,明确相关软件程序和数据的各方面设计原则及高阶架构。技术架构阶段,或服务化架构下,主要是明确技术实现框架、组件(服务)划分等落地细则。随着市场和用户需求的持续变化,以上建模方法中的活动也应该持续迭代进行。更由于这些变化不可预期,我们更应该关注建模活动带来的相关人员和团队认知的提升,不同视角的架构视图是阶段性共识的可视化呈现。对于架构视图,我们推荐大家采用类似 C4(https://c4model.com/)这样的轻量级可视化工具,重要的是关键人群之间的沟通、论证和确认。一言以蔽之,我们更关注产生企业架构的建模协作活动和实践工艺,而采用轻量级治理流程和过程文档。我们认为这样的建模方法符合于《敏捷宣言》所倡导的工作方式,因为:● 更强调人通过互动协作的认知提升,而不拘泥于每个活动的专业对口;● 更强调建模工作的迭代演进,而不拘泥于追求某一个时刻的绝对明确;● 更强调价值驱动,而不拘泥于现有业务的框架;● 更强调持续响应变化,而不拘泥于繁琐的流程和文档。任何方法都存在局限性,从数字化企业的视角,这套方法不包含两个重要方面:商业模式和组织文化。前者不能脱离各行业背景,在这个产业互联的时代,行业的重塑、整合、创造不断发生,着实很难抽象出相对能够广泛应用的方法。文化则是一个需要更多阅历的领域,就现在的个人经历来总结组织文化的方法,难免贻笑大方。下文中我们将整体介绍这个敏捷建模方法框架的含义,三个建模过程和两大运营闭环的细节,将在后续的文章中进一步展开。三个建模过程从业务架构设计到最后的技术架构落地,我们抽象了三个高阶建模过程域,分别是:价值建模、领域建模和组织建模。通过这三大过程域帮助企业明确端到端的建模活动,从而能够高效组织不同角色协同完成整个企业架构的设计。建模过程中应该遵循“共识大于正确性”的原则:企业架构每个阶段的产出是相关角色或团队协作过程中形成的共识,而不是某个专业角色或团队的单独交付物。在任何一个时间点,都应该坦诚认知的局限性,通过保持协作的开放性来兼收并蓄。一、价值建模:面向商业成功业务架构一直以来被认为是企业架构的起点,然而面对这个数字化时代,真正的起点应该是我们的客户/用户,这点已经成为了企业管理者们的普遍共识 —— 只有持续创造客户/用户价值,才能够实现企业的持续发展。由此,我们认为针对客户/用户的价值建模是数字化企业的必然起点。企业需要针对自身的行业及客群定位,确定相关的价值模型,作为不同专业背景角色同事们共识的基础。在很多企业中,我们看到业务和技术的融合都被提升到了组织战略层面,但由于没有从价值建模出发,在实际的执行过程中没有建立起来统一语言,造成客观上难以融合的困局。(招商银行采纳的价值三角模型,让组织能够围绕客户价值来行动。来源于 TWLive 2021 年分享:https://insights.thoughtworks.cn/cmb-value-driven-lean-transformation/)我们也要正视数字化技术带来越来越多元化的价值创造可能性,一家企业可能同时经营非常不同的业务模式,比如不少互联网 2C 服务起家的企业希望抓住下一波企业 2B 服务的浪潮,这样的场景下,应该有针对性的不同价值模型。而不应该由于是一家企业,所以就强制性只能有一套价值模型或一套企业架构。驾驭这种多元化是数字化企业未来的核心竞争力。(某金融机构建立的价值模型示例。)在共识的价值模型下,首先还是需要从产品/服务组合的视角去明确优先级,切忌搞大而全,时刻保持对变化的敬畏心。敏捷宣言签署者之一的 Jim Highsmith 老先生为此提供了一套比较完整的方法框架 EDGE,在《EDGE:价值驱动的数字化转型》一书中有比较完整的介绍。其中的关键实践精益价值树(Lean Value Tree,LVT)在亢江妹老师的《轻量级规划实践方法——精益价值树》也有了具体的介绍。明确了企业级的价值定位,产出业务架构的方法和实践已经有不少的积累。比如服务设计(Service Design)方法,从关键的用户旅程切入,通过端到端的用户场景来明确用户触点及前后台的支撑系统。(服务设计方法下的用户场景化梳理,从用户行为出发,明确能力支撑及前、后台的业务服务设计。)具体推荐的方法和实践我们将在后续专门的系列文章中展开。这里值得提醒企业的管理者们:价值建模是业技融合的起点,也是一个组织是否真正践行客户为中心的标志。希望大家时刻不忘“客户价值”这个数字化时代的北极星指标!在一些相对信息化积累比较好的行业,如银行业,也可以采用类似付晓岩老师在《企业级业务架构设计:方法论与实践》一书中介绍的工序比较明确的方法。但仍然需要注意定期审视用户价值随着市场变化而发生的迁移。二、领域建模:面向统一语言软件行业几十年的积淀形成了一个共识原则:关注点分离(Separation of concerns,SOC)—— 在复杂场景中,把不同的关注点分离开来,分别处理,以应对复杂性。这个原则最早由图灵奖获得者,荷兰计算机科学家埃格斯·迪克斯特拉(Edsger W. Dijkstra)在上世纪 70 年代提出,而后成为了我们在计算机建模领域及系统设计领域的底层范式。我们时下的系统和平台架构某种意义上是其支撑的复杂业务的一种映射,所以我们在这个阶段处理的问题是比产生业务架构更为挑战的。在此基础上,需要再次提醒大家对于变化的预期,即使当下再完美的业务架构也会在未来某个时刻变得不合时宜的,所以系统和平台架构必然需要考虑面向未来持续修改的灵活性。这是一个很难解决的命题,要求更深层次的业务和技术人员的融合,背后是我们需要在企业里建立一套业务和技术人员都能够理解的“普通话”。2003 年提出的领域驱动设计(Domain Driven Design,DDD)无疑给我们提供了统一语言的落地思路。很多人认为 2015 年开始流行的微服务带火了 DDD,但实际上是由于越来越多的企业感受到了在系统架构这个层面日益膨胀的复杂度,同时之前依靠外部购买系统套件搭建起来的信息化系统开始成为新数字化业务发展的障碍。(DDD 思路下的具体方法,类似事件风暴 Event Storming,实质上就是在促进业务和技术人员统一语言的建立。)2017 年为了在国内更好的介绍 DDD 的思路,我也写下来《DDD战略篇:架构设计的响应力》、《DDD战术篇:领域模型的应用》、《DDD实战篇:分层架构的代码结构》三篇。这里就不再赘述,相信很多的国内研发组织已经有实战经验。在这个领域建模阶段,我们仍然还有很长的路要走。走访不少采用了 DDD 的企业会发现大多数都是技术人员在关注 DDD 战术层面的模型应用,讨论最多的是具体的模型如何映射到分层的架构实现。很多企业的研发团队对于和业务建立统一语言这件事情感到失望,甚至于从思想上放弃了这方面的努力。我认为企业架构这个话题在近两年的崛起,是我们解决业务人员加入系统和平台设计阶段的契机。在这个领域建模的过程中,我们需要注意以下两点:建立业务和技术都能够理解的简单语言体系。在这一点上事件风暴 Event Storming 方法给我们呈现了一个简单有效的实例。当然由于各企业所经营业务的多元化,我们还需要更多的方法和实践。划分领域时综合考虑业务和技术的不同约束条件。争论领域到底是业务的、还是技术的是毫无意义的,我们产出的系统或平台领域划分是综合考虑企业经营情况的结果,这里面既有我们对业务相关性的考虑,也有我们对于底层运算平台特性的利用。基于以上两点,我们认为一个良好的领域建模过程首先要让大家明确使用的语言体系,即不论是业务还是技术,都需要学会普通话。然后是一套行之有效的协作流程和实践,能够保证大家在正向约束的条件下进行领域建模,产出系统和平台架构。最后,在这个阶段不少组织存在对于产出物的纠结。业务侧认为需要看到具体的 UI 才踏实,技术侧觉得没有代码框架都是虚幻。我们并不否定一些界面视图或技术原型可能在确认共识方面的必要性,但重要的是达成共识的协作过程。即使这些细节的文档材料对于不同的个体来说也是有不同理解的,而过于细节的材料反而容易造成未参与研讨过程的文档读者迷失在不必要的细节关注里。三、组织建模:面向团队演进长久以来,在具体的软件架构上,我们更多还是从技术范式和框架的视角在设计,从简单的 MVC 架构 web 应用,到时下 SaaS、PaaS、IaaS 的分层模型。被忽略的一个客观事实是:软件开发仍然是强依赖于人的行业,流程、架构和工具某种意义上都必须围绕如何让软件开发个体和团队更高效作为出发点。在软件行业里,我们也逐步形成了对于康威定律的共识—— 组织形态决定产品形态。Conway’s law: Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.Melvin Conway (1967)简要翻译:组织设计的产品/服务等价于这个组织的沟通结构。这个定律对于持续变化的市场和客户需求来说是非常不利的,即我们目前的组织结构会随着未来的变化而变得不合时宜。这种不合时宜会反映出组织交付的产品和服务不能够满足市场和客户的需求。在这个时代,运营超过三年的研发组织或多或少都经历了这样的痛苦,很多的“遗留系统”实际上就是这样产生的。这背后的核心原因是我们的组织结构并没有随着外界的变化而变化,大家过多地期望仅仅是从技术的角度去调整架构,让各个组件更为灵活,但却忽略了组织结构才是长期的制约因素。每次识别出的技术架构问题,往往在最后落地时没有了组织支撑,成为了空中楼阁。由此,我们希望直接从组织结构视角去建模,通过组织的划分及交流沟通结构的确立来表达对应的服务和技术架构。从这个视角出发,团队拓扑 Team Topologies 已经给我们提供了非常好的方法,弥补了过去我们在组织视角的两大盲点:组织内部团队的划分没有明确的目的驱动。针对技术本身的复杂度,组织划分成小团队是一种常态,这不仅仅是开发效率上的考量,也是出于不同目的性的考虑。比如在功能开发团队之上,我们往往会有跨功能的平台团队存在,解决一些共性的能力封装问题;团队和团队之间的沟通互动没有明确的设计。多个团队的协同问题在各个研发组织里十分普遍,经常有不同的角色抱怨“会多”。大家并没有刻意去规划团队和团队之间合理的互动模式,在具体协作过程中自然也无法明确哪些会议是合理的,哪些是由于某个团队工作不到位造成的。(团队拓扑方法下的组织结构和交互模式示例:Team Topologies at PureGym)通过团队拓扑来完成组织建模对于我们“逆康威定律”的帮助是巨大的,业务和系统架构的变化直接就会映射到团队结构的变化上,而团队的变化自然会驱动技术架构的改变。当一个简单 MVC 架构的 web 应用随着市场拓展而越来越复杂的时候,这种变化展现在组织建模上很可能的结果是前、后端团队的分离,这种团队的分离自然而然牵引了架构上的前后端分离。值得一提的是,在云原生和微服务为主导的技术架构时代,大家更容易忽视组织结构的问题。由于单个微服务对比传统架构的代码量少很多,对应的开发团队自然小很多,无形中给了大家组织已经是灵活小团队的假象。然而,不能忽视的是业务的复杂度依旧,多个微服务的集群才能真正实现业务,小团队组织结构下可能增加我们的沟通互动成本,并且组织结构可能形成“静态小团队膨胀”,即当一个新需求出现时,团队不是去考虑是否应该改变现在的微服务,而是默认增加新服务。长此以往,微服务的个数越来越多,小团队之间的沟通越来越繁琐,开发的效率越来越低。所以考虑团队划分的演进是我们保持高效组织生态的必然。两大运营闭环面对持续的变化,我们拥抱敏捷的工作方式,由此也产生了在保证数字化业务持续经营的两大运营闭环,分别是:“顺时针”的市场驱动,和“逆时针”的创新驱动。我们认为在企业架构中明确这样的持续运营闭环是保证大家采用“动态”视角来看待持续建模工作的关键。这正如任何成功的数字化产品和服务,上线面客仅仅是开端,真正的客户价值创造关键是后续的持续运营和迭代演进。这也是为什么我们在企业架构设计过程中,需要从“建模”活动视角来强调这种可持续性。第一环:“顺时针”市场驱动科学应变不论是业务架构还是最后落地的微服务,都是服务于我们在价值建模过程中认定的商业机会。根据企业经营的情况,初始的价值认定会得到验证,而根据验证结果我们就有必要进行业务架构、系统架构的调整,最终驱动技术落地上的迭代。这样的市场驱动也适用于持续的新机会发现,包括一些新技术驱动下的业务可能性的探索。需要强调这并不意味着我们只有一套大而全的业务模型涵盖所有可能业务,相反由于这些新产品和服务的持续探索,一家企业很可能在这些新领域采用独立的、更为轻量级的架构模型,从而能够保持在投资上的灵活性。(EDGE 框架中轻量级价值驱动的战略决策机制可作为市场驱动运营闭环的参考。)在落实这样的运营闭环时,我们应该有相关的管理部门或赋能团队来保证闭环的持续运作,特别是在一些拥有上千人研发队伍的大型组织里。EDGE 里首次提出的“价值实现团队”(Value Realization Team,VRT)就可以做为一个很好的参考,帮助组织推动这个顺时针运营闭环的持续落地。第二环:“逆时针”创新驱动主动求变在这个充满挑战和机遇的市场环境下,创新正成为一家企业的生存必备能力,但大部分组织在如何有效进行创新上却存在很大困惑,更不要说建立支持持续创新的架构。虽然商业创新很多时候可以从商业模式的打造上切入,很多企业的高管也在强化自身的战略投资能力。但不可否认让企业内部的团队,甚至个体,发挥自身的创新能力,已经成为一家企业是否建立数字化基因的基本衡量之一。由此我们需要在建模活动中支持团队主动发起变化,不少的企业都在利用虚拟团队进行跨产品和服务的整合创新,而过去数年全球在学习型组织方面的研究,也为我们提供了基于实践社区 Community of Practice,CoP 的持续运营方式。CoP 围绕着一群有共同关注或热情的人,定期展开互动学习和创新尝试,比如基于自动化技术 RPA 的 CoP,或者人工智能方面的算法 CoP。这种机制的重要性在于保持团队对于市场和技术发展的开放性,通过持续多点尝试来主动发起改变。(基于实践社区 CoP 的虚拟社区组织结构示意,通过 CoP 的机制建立持续学习和创新的组织基因。)不少企业在激发自身产品和服务一线创新的组织机制上,采取了成立内部或联合外部的孵化器模式,允许来自于不同团队的员工自由组队,提出基于企业赛道或能力平台的创新想法,并提供必要的落地支撑。这种模式短期可能取得不错的效果,但需要持续推进长效机制的建立,避免成为赶时髦的昙花一现。甄别借鉴,与时俱进开篇对比了 TOGAF 和 Zachman 这样的经典企业架构方法,帮助大家明确我们为什么从“建模”的视角来切入现代数字化企业架构。但这些经典方法仍然是值得肯定的,它们的提出也是源自于一些先进企业之前数十年推进信息化工作的提炼和总结。对于很多企业来说,信息化仍然是数字化的重要支撑,没有良好的信息化系统,数字化业务就无从谈起。从这点出发,我们需要对这些方法的思路和实践进行甄别和借鉴,比如 TOGAF 针对组织架构能力建立的框架 Architecture Capability Framework,就是比较好的帮助组织建立架构治理能力全局视野的可行方法。当然在一些领域,如架构变更管理 Architecture Change Management,和我们这里提出的敏捷建模,就是截然不同的思考。(TOGAF v9,2 建立的知识库:https://www.opengroup.org/togaf)很多研发组织在实践敏捷开发方法时经常会陷入一个“非标准化”误区,即认为敏捷开发都是提倡个人匠艺,团队层面则不存在什么约束。事实上敏捷开发方法面向的是规模化的软件工程,对比传统强流程管控的方法(如 CMMi),在轻量化流程的基础上,实质是增强了对于个人工艺纪律性方面的要求,比如经典的测试驱动开发 TDD,就要求开发者遵循先设计自动化验收测试、再进行功能实现编码的纪律。同样的思路应用到企业架构设计上,我们认可一些主流方法在“流程和工具”方面的积累,我们希望从轻量化的视角去选择性采用。而我们的敏捷建模方法更关注的是协作和工艺上的实践,强调在企业架构设计中“人和互动”带来的组织级认知的持续提升。改变的道路从来都是充满挑战的,在企业架构重要性日益凸显的数字化时代,我们希望通过这个敏捷建模方法 DEAM 的提炼,帮助更多的人意识到软件研发的本质,并能够更多从组织持续成长的动态视角来构建企业架构的能力,从而奠定数字化时代高质量可持续发展的核心组织支撑。作者简介:肖然,ThoughtWorks 中国区创新总经理及 ThoughtWorks 全球 Open ROADS 数字化转型社区咨询委员会成员。计算机算法博士研究生,著作及翻译有《代码管理核心技术及实践》、《人件》、《增强人类》等。肖然作为大型企业数字化转型专家,10 多年来深耕大型 IT 组织精益治理,领导并参与了华为、中兴、招行、中行等诸多国内外客户的数字化转型项目,帮助金融、通讯、零售、物流等众多领域领先企业加速现代数字化业务转型。依托 ThoughtWorks 全球科技视野和本地化服务洞察,通过敏捷、设计思维、DevOps、数据驱动等一系列方法帮助企业拥抱技术带来的行业颠覆,实现企业内部无缝协作,充分运用先进技术快速识别并抓住新商机。在科技快速迭代的今天,肖然希望从更广阔的跨行业视角审视新兴趋势,为各行业呈现数字化经济深刻洞见。肖然目前关注于科技驱动的产业生态未来,如开放银行(Open Banking)和 5G 等科技浪潮下各领域机遇和挑战。
Now in Android #13 - 最新 Android 动态分享
相信很多安卓开发者已经注意到 Google 推出的全新系列博客 Now in Android,向全世界开发者介绍 Android 的最新发展动态。从去年八月一号发出第一篇 Now in Android: Episode #1 , 到最近的 Now in Android #13,每一篇都值得大家一看。虽然 Google 也会推出 Now in Android 中文版,但基本要比 Medium 上晚半个月左右。好像不是 Now in Android ,应该是 Past in Android 。为了让大家也能第一时间了解最新信息,我准备同步跟进 Now in Android ,第一时间为大家带来中文介绍。这里不会逐字逐句翻译,根据段落大意提炼总结。读者们也可以点击文末的 阅读原文 直接查看原文。下面进入正题。作者首先吐槽了 13 这个数字。13 在西方国家是个不吉利的数字,所以你可以把本篇当做 #14 。当下一篇又发布 #14 的时候,告诉自己这肯定是软件错误。还挺幽默。下面就来说说过去两周的一些值得关注的事情。Android 11 :首个开发者预览版对安卓开发者来说,过去两周的一个大新闻就是 Android 11 首个开发者预览版发布了。你可以下载适用于 Pixel 2 / 3 / 3a / 4 设备的系统镜像,开始体验这个全新的版本,并开始测试你的 App 了。简单说说首个开发者预览版本的新特性。5G 支持。新的 动态计费状态 API 和 带宽估测 API 。气泡 。气泡内置于通知系统中。它们悬浮在其他应用内容之上,并会跟随用户移动到任何位置。气泡可以展开以显示应用功能和信息,并可在不使用时收起。在 Android 10 中引入,但是隐藏在开发者选项中,默认禁用。现在已经启用了。单次权限 。提供了类似 iPhone 的权限机制,用户可以选择赋予临时的单次权限。仅仅当你的应用可见或者前台服务正在运行,才具有权限。一旦离开应用,下次仍需用户授予权限。分区存储 在 Android 10 引入,本次预览版中的改进包括可选的媒体原始文件路径访问、更新过的 DocumentsUI、MediaStore 中的批量编辑操作。生物验证 API 。扩展了生物验证的支持,以满足各种设备的需求。BiometricPrompt 现在支持三种不同颗粒度级别的身份验证类型: 强、弱和设备凭据。同时兼容了 AndroidX BiometricPrompt 。Data blob 。现在可以使用 BlobStoreManager 在应用之间安全快速的共享大型二进制数据对象。这对大文件下载,共享 ML 模型很有用。关于 Android 11 的更多信息,请查看 Android 开发者博客。Android Sutdio3.6Android Studio 发布了 3.6 稳定版,并且一如以往尿性的没过几天就发布了 3.6.1 。具体更新内容就不细说了,这里推荐一篇 掘金的一篇文章 Android Studio 3.6 发布啦,快来围观 。还是提一点,View Binding 发布了,虽然对我来说并没有想使用它的冲动。4.0: BetaMotion Editor,MotionLayout 的可视化编辑器,帮助你构建更丰富的动画。实时布局检查器。期待中......4.1: Canary4.0 release 中已经删除了 Jetpack Compose 编译器。如果你想体验 pre-alpha 版本的 Compose UI 工具,你需要 4.1 版本。这么说,Jetpack Compose 又跳票了~后台定位指南问: 用户隐私中最重要的三件事情是什么? 答: 定位,定位,定位。官方文档提供了关于后台请求定位的最新信息。Dynamic Feature Module Testing这个就不多说了,反正国内也用不了。Material Motion动画是个好东西,但是比较难实现,特别是元素和页面之间丰富的过度动画。Material Design 团队最近发布了一篇全面的 文档,同时也发布了 Material Design Components 类库的 1.2.0-alpha05 版本。文档戳我 !Material-Design 团队文章文章Nick Butcher 发布了两篇 Android Style 系列的文章,都是和主题属性(Theme Attributes) 相关。Android Styling: Common Theme AttributesAndroid Styling: Prefer Theme AttributesUse view binding to replace findViewByIdView Binding 是 Android Studio 中集成的一项功能,让你可以轻松获取布局中视图的引用,并且是类型安全的,而无需使用众所周知的冗长乏味的 findViewById() 。我暂时还没有使用它。我更喜欢 Kotlin Extension 和 DataBinding 。Using BiometricPrompt with CryptoObject: How and WhyIsai Damier 介绍了如何使用密码学和生物识别来保证数据安全,特别是对于政府,金融,健康和企业应用。这里是 代码示例 。Code Sample :生物识别登录android/security-samples该示例展示了如何使用 AndroidX biometric library 正确集成生物认证。视频Vector Assets如何使用 Vectors 提供清晰,可调整大小,生动的图像。Sealed Classes这是一个 Kotlin 系列,之前已经介绍过 inline 、type alias 等。AndroidX Releases最近发布的稳定版:Fragment 1.2.2Media2 1.0.3Room 2.2.4Transition 1.3.1主要都是 bug fix ,Fragment 添加了一些有用的 link 检查。Thanks to Nick Butcher.
阿里云DNS管控平台,新一代DNS解析管理及分发系统
【阅读原文】戳:阿里云DNS管控平台,新一代DNS解析管理及分发系统作者:沈建伟(如鹏)“万物互联,百川赴海。”随着云计算的普及,以及5G万物互联时代的到来,为助力企业数字化转型,对“寻址解析服务”提出了新的挑战:极致的高性能、高可用性、高可扩展性、云端融合、智能化调度等。作为亚洲最大的解析服务提供商,应对这些挑战,阿里云DNS团队率先出征,打磨出了新一代DNS解析管理及分发系统,这个系统,就是今天我们这篇文章的主角:阿里云DNS管控平台。1.什么是“阿里云DNS管控平台”?阿里云DNS管控平台,在阿里云DNS系统的位置,一侧连接B端企业客户,一侧连接分布在阿里云全球region的DNS集群。“阿里云DNS管控平台”的核心能力是为企业客户提供高性能的、高可用性的、高可扩展的、云端融合的解析管理服务,提供统一的友好的解析管理界面(包括管理控制台及openAPI),并把解析变更数据快速分发到全球DNS集群上。2.“阿里云DNS管控平台”之高性能为应对万物互联时代海量解析带来的挑战,“阿里云DNS管控平台”解析变更的性能指标支持100万TPS、1秒分发到全球各DNS节点。构建高性能的“阿里云DNS管控平台”其核心设计思路包括:1. 通过异步化解决服务间的强依赖问题,让部署更灵活、简单;2. 通过sharding机制突破单库单数据源的存储性能瓶颈,让系统在100万TPS内可平滑伸缩;3. 通过多级队列解决数据有序、并行处理、数据分发问题,保障数据变更的正确性及高吞吐量;4. 通过幂等性、重试、及补偿机制解决数据的一致性问题;5. 通过私有网络在“阿里云DNS管控平台”所在中心Region与DNS集群所在边缘Region间提供高效的传输通道,保障数据能在1秒分发到全球各DNS节点。3.“阿里云DNS管控平台”之高可用性DNS作为一种基础设施服务,其整个系统的稳定性不言而喻。“阿里云DNS管控平台”作为解析数据的变更及分发系统,随时都需要支持好客户做解析变更,尤其是在客户做容灾切换的场景下更是如此,这就需要“阿里云DNS管控平台”自身具有极高的可用性。除了“阿里云DNS管控平台”内部各服务本身要消除单点、region内双AZ可用、做好监控报警快恢外,还要做好跨城容灾能力。针对跨城容灾场景,“阿里云DNS管控平台”的设计是异地双活。“阿里云DNS管控平台”整个系统采用双region部署,利用智能线路解析做入口请求流量切分,切分后流量分别进入到每个region并在region内做闭环处理,数据层做数据实时的双向同步,保证每个region都有全量数据。这样在任何一个region出现问题后就可以把出问题region的流量全部切换到正常region上去,保证业务不中断并能持续提供服务。4.“阿里云DNS管控平台”之高可扩展性可扩展性对系统的持续升级迭代至关重要,往往也间接影响着系统的稳定性。大家常看到或听到因为新需求的发布而导致系统产生故障的案例,多数是因为系统的可扩展性不佳,不能很好的满足开闭原则,改一处则动全身,所以在“阿里云DNS管控平台”的设计之初我们就把系统的可扩展性作为一个非常重要的考量维度。“阿里云DNS管控平台”通过引入DDD的设计方法论,让模型的设计更加统一,让模型分层分模块的边界更加清晰,让各模型的职责更加单一,逻辑更加内聚,通过引入扩展点机制从框架层面统一管理易发生变化的逻辑,让差异化的逻辑互不影响相互隔离,另外通过引入SPI机制把对外部尤其是中间件的依赖SPI化,使对外部的依赖最小化,方便中间件升级切换。5.“阿里云DNS管控平台”之云端融合随着“云端一体”产品战略的发布及落地,云端互管、统一管理是其核心特性(我们把客户机房私有化部署的DNS也定义一种特殊的端)。客户可以在端侧通过私有化部署的“阿里云DNS管控平台”,统一管理私有化部署的DNS服务与云上DNS服务,实现云下云上互联互通统一管理,为客户管理与运维DNS服务提供全局视角,极大提升客户的效率与使用体验。面向未来AIDNS智能化的流量调度万物互联时代到来,随着各类应用的爆发,各种终端、设备的接入,仅依靠静态解析配置、基于简单规则的流量调度与容灾切换,已不能满足未来海量终端设备对解析变更及分发的要求。未来,我们需要在采集应用、服务、网络、终端、请求量等各数据的基础上,加上智能算法,一同构建智能化的流量调度大脑AIDNS。通过AIDNS提供智能化、动态化的解析配置能力,能够让请求流量以最短的路径、最快的速度到达能提供最佳服务质量的应用实例,能够更加精细化地自动过滤掉各种非正常流量,能够对应用或服务自动做扩缩容,能够对应用部署规划提供建议等。 未来已来,阿里云DNS团队将继续开拓创新、迎接挑战,推进DNS更好的服务客户、服务社会。我们是阿里巴巴云计算和大数据技术幕后的核心技术输出者。欢迎关注 “阿里云基础设施”同名微信、微博、知乎获取关于我们的更多信息~
Android11的到来,你如今被OUT了吗?
1、前言*最近看到一条新闻,Android 11(version 30,Andorid R)最终Beta版 如期发布,看到这个新闻我知道我不能再拖了,再不好好准备好迎接Android11的到来,到时候迎接我的就是客户的指责,甚至老板的一封休书了 😂。今天就和大家一起看看Android11到底改了些什么,以及最重要的,我们需要怎么适配?targetversion不改到30,是不是就不用适配了呢?以下我分为两部分讲述,分别是以Adnroid11 为目标版本的应用(targetSdkVersion>=30才有影响)所有应用在Android11设备上适配改动(无论targetSdkVersion是多少,只要在Android11设备上运行的应用都有影响)为什么先说targetSdkVersion>=30的模块呢?因为一般来说为了Google为了让我们更长时间适应新的内容以及保障线上应用的稳定,都会把改动大的,需要花时间适配的内容放到新的targetSdkVersion对应的应用上,如果你暂时没有适配targetSdkVersion30的需求,也可以看看第二模块,看看是否有涉及你的应用相关内容。GOGOGO!Tips:此适配文章会不间断更新,根据Android11发布进度调整,欢迎点赞关注。(打⭐的格外注意哦)2、适配targetSdkVersion30此模块的修改内容只针对targetSdkVersion 30或者以上才生效。分区存储强制执行⭐对外部存储目录的访问仅限于应用专属目录,以及应用已创建的特定类型的媒体。关于分区存储,在Android10就已经推行了,简单的说,就是应用对于文件的读写只能在沙盒环境,也就是属于自己应用的目录里面读写。其他媒体文件可以通过MediaStore进行访问。但是在android10的时候,Google还是为开发者考虑,留了一手。在targetSdkVersion = 29应用中,设置android:requestLegacyExternalStorage=“true”,就可以不启动分区存储,让以前的文件读取正常使用。但是targetSdkVersion = 30中不行了,强制开启分区存储。当然,作为人性化的android,还是为开发者留了一小手,如果是覆盖安装呢,可以增加android:preserveLegacyExternalStorage=“true”,暂时关闭分区存储,好让开发者完成数据迁移的工作。为什么是暂时呢?因为只要卸载重装,就会失效了。以下是关于分区存储会遇到的所有情况,给大家罗列出来了,先上代码:fun saveFile() {
if (checkPermission()) {
//getExternalStoragePublicDirectory被弃用,分区存储开启后就不允许访问了
val filePath = Environment.getExternalStoragePublicDirectory("").toString() + "/test3.txt"
val fw = FileWriter(filePath)
fw.write("hello world")
fw.close()
showToast("文件写入成功")
}
}分情况运行:1) targetSdkVersion = 28,运行后正常读写。2) targetSdkVersion = 29,不删除应用,targetSdkVersion 由28修改到29,覆盖安装,运行后正常读写。3) targetSdkVersion = 29,删除应用,重新运行,读写报错,程序崩溃(open failed: EACCES (Permission denied))4) targetSdkVersion = 29,添加android:requestLegacyExternalStorage=“true”(不启用分区存储),读写正常不报错5) targetSdkVersion = 30,不删除应用,targetSdkVersion 由29修改到30,读写报错,程序崩溃(open failed: EACCES (Permission denied))6) targetSdkVersion = 30,不删除应用,targetSdkVersion 由29修改到30,增加android:preserveLegacyExternalStorage=“true”,读写正常不报错7) targetSdkVersion = 30,删除应用,重新运行,读写报错,程序崩溃(open failed: EACCES (Permission denied))ok,那到底应该怎么改呢?三种方法访问文件:1)应用专属目录//分区存储空间
val file = File(context.filesDir, filename)
//应用专属外部存储空间
val appSpecificExternalDir = File(context.getExternalFilesDir(), filename)2)访问公共媒体目录文件val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc")
if (cursor != null) {
while (cursor.moveToNext()) {
val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
println("image uri is $uri")
}
cursor.close()
}3) SAF(存储访问框架–Storage Access Framework)val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, 100)
@RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
if (requestCode == 100) {
val uri = data.data
println("image uri is $uri")
}
}具体还有很多操作可以看看网上关于分区存储的资料,因为Android10已经出来很久了,所以资料还是很多的。说到这里可能又有人问了,那我的应用就是个手机管理器,总不能不让我清其他应用的缓存了吧,有办法!Android提供了两个intent入口:调用ACTION_MANAGE_STORAGE intent 操作检查可用空间。调用ACTION_CLEAR_APP_CACHE intent 操作清除所有缓存。说来说去,反正应用数据私有化是大势所趋,还是早点适配分区存储,别等以后手机只有沙盒机制的时候,就来不及了。媒体文件访问权限 ⭐为了在保证用户隐私的同时可以更轻松地访问媒体,Android 11 增加了以下功能。执行批量操作和使用直接文件路径和原生库访问文件。1)执行批量操作这里的批量操作指的是Android 11 向 MediaStore API 中添加了多种方法,用于简化特定媒体文件更改流程(例如在原位置编辑照片),分别是:createWriteRequest() 用户向应用授予对指定媒体文件组的写入访问权限的请求。createFavoriteRequest()用户将设备上指定的媒体文件标记为“收藏”的请求。对该文件具有读取访问权限的任何应用都可以看到用户已将该文件标记为“收藏”。createTrashRequest() 用户将指定的媒体文件放入设备垃圾箱的请求。垃圾箱中的内容会在系统定义的时间段后被永久删除。createDeleteRequest() 用户立即永久删除指定的媒体文件(而不是先将其放入垃圾箱)的请求。直接看个例子:val urisToModify = listOf(uri,uri,...)
val editPendingIntent = MediaStore.createWriteRequest(contentResolver,
urisToModify)
// Launch a system prompt requesting user permission for the operation.
startIntentSenderForResult(editPendingIntent.intentSender, EDIT_REQUEST_CODE,
null, 0, 0, 0)
override fun onActivityResult(requestCode: Int, resultCode: Int,
data: Intent?) {
when (requestCode) {
EDIT_REQUEST_CODE ->
if (resultCode == Activity.RESULT_OK) {
/* Edit request granted; proceed. */
} else {
/* Edit request not granted; explain to the user. */
}
}
}
传入uri的集合,获取用户的同意后,就可以进行操作了。2)直接文件路径和原生库访问文件没错!Android11又恢复了使用直接文件路径访问访问媒体文件!哈哈,这样就方便多了。也就是除了 MediaStore API之外还有两种方式可以访问媒体文件:File API。原生库,例如 fopen()。那Android10咋办呢??要不就用MediaStore,要不就直接把分区存储关了吧(requestLegacyExternalStorage=true)所有文件访问权限 ⭐虽然说了这么多,但是还有些应用就要访问所有文件,比如杀毒软件,文件管理器。放心,有办法!MANAGE_EXTERNAL_STORAGE 这不来了吗。这个权限就是用来获取所有文件的管理权限。🌰:<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
val intent = Intent()
intent.action= Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
startActivity(intent)
//判断是否获取MANAGE_EXTERNAL_STORAGE权限:
val isHasStoragePermission= Environment.isExternalStorageManager()来张截图过过瘾:电话号码相关权限 ⭐Android 11 更改了您的应用在读取电话号码时使用的与电话相关的权限。具体改了什么呢?其实就是两个API:TelecomManager 类中的 getLine1Number() 方法TelecomManager 类中的 getMsisdn() 方法也就是当用到这两个API的时候,原来的READ_PHONE_STATE权限不管用了,需要READ_PHONE_NUMBERS权限才行。下面具体说说,targetSdkVersion修改到30,然后运行一个获取电话号码的程序ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_PHONE_STATE), 100)
btn2.setOnClickListener {
val tm = this.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val phoneNumber = tm.line1Number
showToast(phoneNumber)
}崩溃了:java.lang.SecurityException: getLine1NumberForDisplay:
Neither user 10151 nor current process has
android.permission.READ_PHONE_STATE,
android.permission.READ_SMS,
or android.permission.READ_PHONE_NUMBERS预想之中哈,Andmanifest.xml中注册好权限,并且添加动态权限申请:<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_PHONE_NUMBERS), 100)
搞定,如果你只需要获取手机号码这一个功能,也可以只申请READ_PHONE_NUMBERS这一个权限:<uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />自定义消息框视图被屏蔽 ⭐从 Android 11 开始,已弃用自定义消息框视图。如果您的应用以 Android 11 为目标平台,包含自定义视图的消息框在从后台发布时会被屏蔽可能有人会奇怪了,什么是自定义消息框视图啊?我说英文你就知道了,英文是custom toast views,也就是自定义toast。简单写个代码:Toast toast = new Toast(context);
toast.setDuration(show_length);
toast.setView(view);
toast.show();糟了糟了,自定义toast被弃用了?我们项目就是用的这个啊!不用担心,只是不允许自定义toast从后台显示了。比如我写一个3秒后再显示toast,然后应用一打开就进入后台,看看会发生什么:Handler().postDelayed({
IToast.show("你好,我是自定义toast")
}, 3000)
W/NotificationService: Blocking custom toast from package com.example.studynote due to package not in the foreground啥也没显示,只是发出来一个警告。所以不用太过担心,如果实在需要后台显示,就用普通的toast吧!现在需要 APK 签名方案 v2 ⭐对于以 Android 11(API 级别 30)为目标平台,且目前仅使用 APK 签名方案 v1 签名的应用,现在还必须使用 APK 签名方案 v2 或更高版本进行签名。用户无法在搭载 Android 11 的设备上安装或更新仅通过 APK 签名方案 v1 签名的应用。这个介绍已经很明显了吧,如果你的targetSdkVersion修改到30,那么你就必须要加上v2签名才行。否则无法安装和更新。媒体intent操作需要系统默认相机 ⭐从 Android 11 开始,只有预装的系统相机应用可以响应以下 intent 操作:android.media.action.VIDEO_CAPTUREandroid.media.action.IMAGE_CAPTUREandroid.media.action.IMAGE_CAPTURE_SECURE也就是说,如果我调用intent唤起照相机,使用VIDEO_CAPTURE的action,只有系统的相机能够响应,而第三方的相机应用不会响应了。val intent=Intent()
intent.action=android.provider.MediaStore.ACTION_IMAGE_CAPTURE
startActivity(intent)
//无法唤起第三方相机了,只能唤起系统相机这点对普通的相机应用还是有点打击的,官方给的建议是如果要使用特定的第三方相机应用来代表其捕获图片或视频,可以通过为intent设置软件包名称或组件来使这些intent变得明确。5G ⭐Android 11 添加了在您的应用中支持 5G 的功能新的Android11也是支持了5G相关的一些功能,包括:检测是否连接到了5G网络检查按流量计费性首先是检测5G网络,通过TelephonyManager的监听方法:private fun getNetworkType(){
val tManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
tManager.listen(object : PhoneStateListener() {
@RequiresApi(Build.VERSION_CODES.R)
override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
if (ActivityCompat.checkSelfPermission(this@Android11Test2Activity, android.Manifest.permission.READ_PHONE_STATE) != android.content.pm.PackageManager.PERMISSION_GRANTED) {
return
}
super.onDisplayInfoChanged(telephonyDisplayInfo)
when(telephonyDisplayInfo.networkType) {
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> showToast("高级专业版 LTE (5Ge)")
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> showToast("NR (5G) - 5G Sub-6 网络")
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> showToast("5G+/5G UW - 5G mmWave 网络")
else -> showToast("other")
}
}
}, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
}如果是5g网络,就免不了要去判断是不是按流量计费的,否则5G的流量可不是开玩笑的。检测流量计费方法也很简单,监听网络,在回调中判断:val manager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
manager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities)
//true 代表连接不按流量计费
val isNotFlowPay=networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) ||
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
}
})判断该值,如果为 true,则将连接视为不按流量计费。后台位置信息访问权限 ⭐在搭载 Android 11 的设备上,当应用中的某项功能请求在后台访问位置信息时,用户看到的系统对话框不再包含用于启用后台位置信息访问权限的按钮。如需启用后台位置信息访问权限,用户必须在设置页面上针对应用的位置权限设置一律允许选项。什么意思呢?在较低版本的Android系统中,当应用获得前台位置信息访问权限时,也会自动获得后台位置信息访问权限。比如我请求一个前台位置访问权限:requestPermissions(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), 100)授权后,就能同时获取前台位置权限和后台位置权限(ACCESS_BACKGROUND_LOCATION)。但是现在不行了,你必须单独申请后台位置权限,而且,要在获取前台权限之后,顺序还不能乱。requestPermissions(arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100)如果在没获取前台权限的时候执行这个获取后台权限的代码会没反应,等获取前台权限(ACCESS_COARSE_LOCATION)之后,申请后台权限就会跳转到一个新的权限页面了,而且必须选择Allow all the time (始终允许)才能获得后台位置权限,看图:软件包可见性 ⭐Android 11 更改了应用查询用户已在设备上安装的其他应用以及与之交互的方式。使用新的 元素,应用可以定义一组自身可访问的其他应用。通过告知系统应向您的应用显示哪些其他应用,此元素有助于鼓励最小权限原则。此外,此元素还可帮助 Google Play 等应用商店评估应用为用户提供的隐私权和安全性。就是说,Android11中,如果你想去获取其他应用的信息,比如包名,名称等等,不能直接获取了,必须在清单文件中添加元素,告知系统你要获取哪些应用信息或者哪一类应用。比如我这段查询应用信息的代码:val pm = this.packageManager
val listAppcations: List<ApplicationInfo> = pm
.getInstalledApplications(PackageManager.GET_META_DATA)
for (app in listAppcations) {
Log.e("lz",app.packageName)
}在Android11版本,只能查询到自己应用和系统应用的信息,查不到其他应用的信息了。怎么呢?添加元素,两种方式:1)元素中加入具体包名<manifest package="com.example.game">
<queries>
<package android:name="com.example.store" />
<package android:name="com.example.services" />
</queries>
...
</manifest>
2)元素中加入固定过滤的intent<manifest package="com.example.game">
<queries>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/jpeg" />
</intent>
</queries>
</manifest>可能还是有人会疑惑,那我的应用是浏览器或者设备管理器咋办呢?我就要获取所有包名啊?放心,Android11还引入了 QUERY_ALL_PACKAGES 权限,清单文件中加入即可。但是Google Play可不一定能滥用哦,它为需要QUERY_ALL_PACKAGES 权限的应用会提供相关指南,但是还没出来,具体要看后面的消息了。至于国内应用市场。。。(希望能有个应用市场一统天下好好管理这混乱的市场吧!)文档访问限制为让开发者有时间进行测试,以下与存储访问框架 (SAF) 相关的变更只有在应用以 Android 11 为目标平台时才会生效。上文存储的时候说过可以通过SAF(存储访问框架–Storage Access Framework)来访问公共目录,但是Android11再次升级,部分目录和文件不能访问了,具体如下:无法再使用 ACTION_OPEN_DOCUMENT_TREE intent 操作请求访问以下目录:内部存储卷的根目录。设备制造商认为可靠的各个 SD 卡卷的根目录,无论该卡是模拟卡还是可移除的卡。可靠的卷是指应用在大多数情况下可以成功访问的卷。Download 目录。无法再使用 ACTION_OPEN_DOCUMENT_TREE 或 ACTION_OPEN_DOCUMENT intent 操作请求用户从以下目录中选择单独的文件:Android/data/ 目录及其所有子目录。Android/obb/ 目录及其所有子目录。在元数据文件中声明“无障碍”按钮使用情况从 Android 11 开始,您的无障碍服务无法在运行时声明与系统的“无障碍”按钮的关联。如果您将 AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON 附加到 AccessibilityServiceInfo 对象的 flags 属性,框架就不会将“无障碍”按钮回调事件传递给您的服务。做过无障碍辅助功能的应该都知道AccessibilityServiceInfo要设置flag为FLAG_REQUEST_ACCESSIBILITY_BUTTON,getAccessibilityButtonController方法获取辅助功能按钮控制器,并且可用于查询辅助功能按钮的状态并注册监听器以进行交互和辅助功能按钮的状态更改。但是,Android 11开始,这样写不能获取辅助按钮回调事件了,得换成另外一种写法。在元数据文件(通常为 res/raw/accessibilityservice.xml)中使用 flagRequestAccessibilityButton 标记声明您的无障碍服务与“无障碍”按钮的关联。设备到设备文件传输如果您的应用以 Android 11 为目标平台,您将无法再使用 allowBackup 属性停用应用文件的设备到设备迁移。系统会自动启用此功能。不过,即使您的应用以 Android 11 为目标平台,您也可以通过将 allowBackup 属性设置为 false 来停用应用文件的云端备份和恢复。android:allowBackup属性代表是否允许应用参与备份和恢复基础架构。如果将此属性设为 false,则永远不会为该应用执行备份或恢复,即使是采用全系统备份方法也不例外(这种备份方法通常会通过 adb 保存所有应用数据)。此属性的默认值为 true。所以这里是不能停用文件的设备到设备迁移,但是可以停用云端备份和恢复。自动重置权限如果应用以 Android 11 为目标平台并且数月未使用,系统会通过自动重置用户已授予应用的运行时敏感权限来保护用户数据。此操作与用户在系统设置中查看权限并将应用的访问权限级别更改为拒绝的做法效果一样。如果应用已遵循有关在运行时请求权限的最佳做法,那么您不必对应用进行任何更改。这是因为,当用户与应用中的功能互动时,您应该会验证相关功能是否具有所需权限。官方说明说的很清楚了,而且只要应用遵循有关在运行时请求权限的最佳做法,也就是每次需要调用权限的时候都会去判断,那么就不会有什么问题。如果需要关闭这个功能怎么办呢?只有引导用户去设置页面关闭了,可以调用包含Settings.ACTION_APPLICATION_DETAILS_SETTINGS action的 Intent将用户定向到系统设置中应用的页面。怎么检查应用是否停用自动重置功能呢?调用 PackageManager的isAutoRevokeWhitelisted()方法。如果此方法返回 true,代表系统不会自动重置应用的权限。前台服务类型从 Android 9 开始,应用仅限于在前台访问摄像头和麦克风。为了进一步保护用户,Android 11 更改了前台服务访问摄像头和麦克风相关数据的方式。如果您的应用以 Android 11 为目标平台并且在某项前台服务中访问这些类型的数据,您需要在该前台服务的声明的 foregroundServiceType 属性中添加新的 camera 和 microphone 类型。举例,如果应用某项前台服务需要访问位置信息、摄像头和麦克风,那么就这样添加:<manifest>
<service ...
android:foregroundServiceType="location|camera|microphone" />
</manifest>
3、适配Android11手机此模块的修改内容针对所有项目在Android11手机上存在的改动,与targetSdkVersion无关。数据访问审核 ⭐为了让应用及其依赖项访问用户私密数据的过程更加透明,Android 11 引入了数据访问审核功能。借助此流程得出的见解,您可以更好地识别和纠正可能出现的意外数据访问。哪些范畴属于用户私密数据呢?其实就是危险权限的调用,所以这个功能就是提供了可以监听危险权限调用的监听。主要涉及到的方法是AppOpsManager.OnOpNotedCallback。无论是应用本身,还是依赖库或者SDK中的代码,只要访问到私密数据(危险权限),都会回调给我们。对于工程庞大或者使用较多SDK的工程比较适合用上这个功能,让自己应用的私有数据管理更加透明规范,否则对于私有数据的使用和管理并不全面和方便。而且还可以对权限使用添加归因,也就是一个tag,标志权限用到了什么地方。方便回调的时候知晓哪里使用了私有数据。🌰来:override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test1)
//创建归因(attribute)
attributionContext = createAttributionContext("shareLocation")
//监听事件
val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() {
private fun logPrivateDataAccess(
opCode: String, attributionTag: String, trace: String) {
Log.i(TAG, "Private data accessed. " +
"Operation: $opCode\n " +
"Attribution Tag:$attributionTag\nStack Trace:\n$trace")
}
override fun onNoted(syncNotedAppOp: SyncNotedAppOp) {
syncNotedAppOp.attributionTag?.let {
logPrivateDataAccess(syncNotedAppOp.op,
it,
Throwable().stackTrace.toString())
}
}
override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) {
syncNotedAppOp.attributionTag?.let {
logPrivateDataAccess(syncNotedAppOp.op,
it,
Throwable().stackTrace.toString())
}
}
override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) {
asyncNotedAppOp.attributionTag?.let {
logPrivateDataAccess(asyncNotedAppOp.op,
it,
asyncNotedAppOp.message)
}
}
}
//开启私密数据监听
val appOpsManager =
getSystemService(AppOpsManager::class.java) as AppOpsManager
appOpsManager.setOnOpNotedCallback(mainExecutor, appOpsCallback)
btn1.setOnClickListener {
getLocation()
}
}
fun getLocation() {
val locationManager = attributionContext.getSystemService(
LocationManager::class.java) as LocationManager
if (!checkPermission()) {
return
}
val location: Location? = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
if (location != null) {
showToast("${location.latitude}")
}
}
该例子主要展示了一个获取位置信息的功能,如果调用到getLocation方法,就会触发onNoted回调,回调信息包括危险权限code以及归因。其中OnOpNotedCallback 一共三个回调方法:onNoted 正常情况下都会回调到该方法onAsyncNoted 如果数据访问并非发生在应用调用API期间,就会调用onAsyncNoted(),比如一些监听器的回调。onSelfNoted 在极少数情况下,如果应用将自身的UID传递到 noteOp(),需要调用 onSelfNoted()。最后点击按钮,看下回调的结果日志:Private data accessed. Operation: android:coarse_location
Attribution Tag:shareLocation
Stack Trace:
[Ljava.lang.StackTraceElement;@14f5a16可以看到权限代码:android:coarse_location 以及归因 shareLocation单次授权在 Android 11 中,每当应用请求与位置信息、麦克风或摄像头相关的权限时,面向用户的权限对话框会包含仅限这一次选项。如果用户在对话框中选择此选项,系统会向应用授予临时的单次授权。简单的说,就是在申请与位置信息、麦克风或摄像头相关的权限时,系统会自动提供一个单次授权的选项,只供这一次权限获取。然后用户下次打开app的时候,系统会再次提示用户授予权限。这个影响应该不大,只要我们每次使用的时候都去判断权限,没有就去申请即可。放一张新版本权限获取样式:权限对话框的可见性Android 11 建议不要请求用户已选择拒绝的权限。在应用安装到设备上后,如果用户在使用过程中屡次针对某项特定的权限点按拒绝,此操作表示其希望“不再询问”。这个都算不上改动,只是官方的一个良好建议。建议在用户多次拒绝之后,不要再展示权限申请。Scudo Hardened AllocatorAndroid 11 在内部使用 Scudo Hardened Allocator 为堆分配提供服务。Scudo 能够检测并减轻某些类型的内存安全违规行为。如果您在原生代码崩溃报告中发现与 Scudo 相关的崩溃(例如 Scudo ERROR:),请参阅 Scudo 问题排查文档。Scudo是一种动态的用户模式内存分配器,旨在抵御与堆相关的漏洞,同时保持良好的性能。它是一个开源的项目。Android 11中,将采用这个新的heap分配器,性能更好,更安全。文件描述符排错程序Android 10 引入了 fdsan(文件描述符排错程序)。fdsan 检测错误处理文件描述符所有权的错误,例如 use-after-close 和 double-close。在 Android 11 中,fdsan 的默认模式发生了变化。现在,fdsan 会在检测到错误时中止,而以前的行为则是记录警告并继续。问题来了,fdsan是啥?先要了解fd是啥文件描述符(FileDescriptor) 是Unix/Linux系统文件操作的相关概念,它在形式上是一个非负整数。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。系统的进程也就是使用了这个fd来标示打开的文件,有了它就能对文件做各种操作,获得文件的各种相关信息了。所以fdsan也就是检测文件处理中发生的一些错误。应用使用情况统计信息为了更好地保护用户,Android 11 将每个用户的应用使用情况统计信息存储在凭据加密存储空间中。这就涉及到了UsageStatsManager,UsageStatsManager是Android提供统计应用使用情况的服务。通过这个服务可以获取指定时间区间内应用使用统计数据、组件状态变化事件统计数据以及硬件配置信息统计数据。比如queryAndAggregateUsageStats方法,可以获取指定时间区间内使用统计数据,以应用包名为键值进行数据合并。但是在Android 11 设备中,不好意思,不能随意使用这些信息了。只有当isUserUnlocked()方法返回true的时候,才能正常访问这些数据。也就是以下两种情况:用户在系统启动后首次解锁其设备用户在设备上切换到自己的帐号JobScheduler API 调用限制调试JobScheduler任务调度器,可以在设备空闲时做一些任务处理。Android11中如果你设置为debug模式(debuggable 清单属性设置为 true),超出速率限制的JobScheduler API调用将返回 RESULT_FAILURE。这个有什么用呢?应该可以帮助我们发现一些性能问题,感兴趣的可以自己试试。顺便提下,Jetpack组件WorkManager也是用到了JobScheduler,不熟悉的同学可以去了解下,JobScheduler是由SystemServer进程启动的一个系统服务,所以才可以有这么大的权限。无障碍操作在以前的 Android 版本中,框架会向未正确处理基于点击的无障碍操作的微件分派触摸事件。通常,这些视图会直接处理触摸事件,而不是注册点击监听器。为了在正确定义无障碍操作的应用中创建更一致的行为,Android 11 绝不会分派触摸事件。相反,系统会完全依赖于基于点击的无障碍操作:ACTION_CLICK 和 ACTION_LONG_CLICK。此更改会影响屏幕阅读器的行为。在Android手机上有个预安装的屏幕阅读服务,叫做TalkBack,为视力障碍人士或者视力状态不佳的老年人提供。那我们应用为了让这个阅读器能够读懂你的自定义view操作,必须给与自定义控件定义处理程序,包括点击,长按等操作。原来版本可能对于OnTouchListener也支持无障碍触摸事件,而在Android11中,必须专门制定点击或者长按事件才行了。给个🌰:class TriSwitch(context: Context) : Switch(context) {
// 0, 1, or 2.
var currentState: Int = 0
private set
init {
updateAccessibilityActions()
}
private fun updateAccessibilityActions() {
ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
action-label) {
view, args -> moveToNextState()
})
}
private fun moveToNextState() {
currentState = (currentState + 1) % 3
}
}
一个自定义控件TriSwitch,继承自Switch,由于和Switch的点击效果不一样,所以必须通过替换 ViewCompat.replaceAccessibilityAction() 来重新定义相应的无障碍操作。非SDK接口限制Android 11 包含更新后的受限制非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。在限制使用非 SDK 接口之前,我们会尽可能确保提供公开替代方案。老样子,Android11也会限制一些接口,包括灰名单和白名单,具体看非SDK接口列表。4、总结一路分析下来也可以看到,如果是重要的改动,特别是涉及到崩溃的改动还是放到了targetSdkVersion=30的内容中,这也是每次Android发版的一个潜规则吧,为了最大程度不影响已上线的app所作出的举动。但是,这并不意味我们就可以不改。因为应用可拖不起,用户可拖不起,毕竟升级才能给到用户最好的体验。而且各大应用市场也都会建议或者强制应用升级targetSdkVersion,以便适配最新的手机。所以,赶快重新把Android知识点重新复习一遍吧。下面是我整理出的一些知识点,有兴趣的可以看看。Android核心知识点笔记github