我把QQ空间的网页保存起来,在电脑网页显示脱机状态态下可以打开 反而在有线状态下他会转到链接上,但又打不开?

如何在脱机状态下打开我想看的网页,我放在搜藏夹里好像打不开?_百度知道
如何在脱机状态下打开我想看的网页,我放在搜藏夹里好像打不开?
以前不是会提醒脱机工作什么的么?我不知道怎么弄。请高手指点
我有更好的答案
IE菜单栏里文件-脱机工作 把勾去掉就可以了不提示了
打开页面后点文件菜单下的另存为,将页面保存到本地电脑上
这种方式保存,打开不了啊,用word方式打开,只有文字,而且格式完全变了,没有图片
为什么用word?直接用浏览器打开就行
为您推荐:
其他类似问题
脱机状态的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。Android M新特性Doze and App Standby模式详解2 years ago97收藏分享举报文章被以下专栏收录虽然自己不是他,但我会成为他的影子。{&debug&:false,&apiRoot&:&&,&paySDK&:&https:\u002F\u002Fpay.zhihu.com\u002Fapi\u002Fjs&,&wechatConfigAPI&:&\u002Fapi\u002Fwechat\u002Fjssdkconfig&,&name&:&production&,&instance&:&column&,&tokens&:{&X-XSRF-TOKEN&:null,&X-UDID&:null,&Authorization&:&oauth c3cef7c66aa9e6a1e3160e20&}}{&database&:{&Post&:{&&:{&isPending&:false,&contributes&:[{&sourceColumn&:{&lastUpdated&:,&description&:&虽然自己不是他,但我会成为他的影子。&,&permission&:&COLUMN_PUBLIC&,&memberId&:296070,&contributePermission&:&COLUMN_PUBLIC&,&translatedCommentPermission&:&all&,&canManage&:true,&intro&:&虽然自己不是他,但我会成为他的影子。&,&urlToken&:&magilu&,&id&:6113,&imagePath&:&a23ac5d2dcbc4459.jpg&,&slug&:&magilu&,&applyReason&:&&,&name&:&MAGI的专栏&,&title&:&MAGI的专栏&,&url&:&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fmagilu&,&commentPermission&:&COLUMN_ALL_CAN_COMMENT&,&canPost&:true,&created&:,&state&:&COLUMN_NORMAL&,&followers&:2426,&avatar&:{&id&:&a23ac5d2dcbc4459&,&template&:&https:\u002F\u002Fpic1.zhimg.com\u002F{id}_{size}.jpg&},&activateAuthorRequested&:false,&following&:false,&imageUrl&:&https:\u002F\u002Fpic1.zhimg.com\u002Fa23ac5d2dcbc4459_l.jpg&,&articlesCount&:30},&state&:&accepted&,&targetPost&:{&titleImage&:&https:\u002F\u002Fpic2.zhimg.com\u002Fa2f8b290f_r.jpg&,&lastUpdated&:,&imagePath&:&a2f8b290f.jpg&,&permission&:&ARTICLE_PUBLIC&,&topics&:[],&summary&:&作者:timorzheng出品:QQ空间终端开发团队本文首发于QQ空间终端开发团队的官方公众号,任何形式的转载之前必须与本人联系。 \u003Cstrong\u003EOptimizing for Doze and App Standby\u003C\u002Fstrong\u003E1. 从Android6.0开始,Android提供了两种省电延长电池寿命的功能:Doze和App Standby;2. 表…&,&copyPermission&:&ARTICLE_COPYABLE&,&translatedCommentPermission&:&all&,&likes&:0,&origAuthorId&:296070,&publishedTime&:&T16:10:25+08:00&,&sourceUrl&:&&,&urlToken&:,&id&:311900,&withContent&:false,&slug&:,&bigTitleImage&:false,&title&:&Android M新特性Doze and App Standby模式详解&,&url&:&\u002Fp\u002F&,&commentPermission&:&ARTICLE_ALL_CAN_COMMENT&,&snapshotUrl&:&&,&created&:,&comments&:0,&columnId&:6113,&content&:&&,&parentId&:0,&state&:&ARTICLE_PUBLISHED&,&imageUrl&:&https:\u002F\u002Fpic2.zhimg.com\u002Fa2f8b290f_r.jpg&,&author&:{&bio&:&个人问题请移步值乎提问&,&isFollowing&:false,&hash&:&ad02ed87e3941cccc6bb1376581badc1&,&uid&:80,&isOrg&:false,&slug&:&m-a-g-i&,&isFollowed&:false,&description&:&聪明的做法可能有一万种,但善良与正确的路只有一条。&,&name&:&MagiLu&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fm-a-g-i&,&avatar&:{&id&:&b3239bbe59ff7749484c&,&template&:&https:\u002F\u002Fpic4.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&memberId&:296070,&excerptTitle&:&&,&voteType&:&ARTICLE_VOTE_CLEAR&},&id&:299533}],&title&:&Android M新特性Doze and App Standby模式详解&,&author&:&m-a-g-i&,&content&:&\u003Cp\u003E作者:timorzheng\u003C\u002Fp\u003E\u003Cp\u003E出品:QQ空间终端开发团队\u003C\u002Fp\u003E\u003Cp\u003E本文首发于QQ空间终端开发团队的官方公众号,任何形式的转载之前必须与本人联系。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch2\u003E\u003Cstrong\u003EOptimizing for Doze and App Standby\u003C\u002Fstrong\u003E\u003C\u002Fh2\u003E\u003Cp\u003E1. 从Android6.0开始,Android提供了两种省电延长电池寿命的功能:Doze和App Standby;\u003C\u002Fp\u003E\u003Cp\u003E2. 表现形式:当设备没有连接到电源,设备进入Doze模式时,系统将通过延迟最近用户没有使用的应用程序的后台CPU运作及网络活动,让应用程序处于App Standby状态,以此来减少电池消耗。谷歌表示,在Nexus5和Nexus6上测试,当屏幕处于关闭状态,平均续航时间提高30%;\u003C\u002Fp\u003E\u003Cp\u003E3. 版本要求:Android6.0(API level 23)及其更高版本;\u003C\u002Fp\u003E\u003Cp\u003E4. 开发者影响:为了保证用户的最佳体验,开发者有必要在Doze和App Standby模式下测试应用程序,及其对代码进行相应的调整。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003EUnderstanding Doze\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E1.设备进入Doze睡眠模式时机:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E用户不操作设备一段时间\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E屏幕关闭\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E设备未连接电源充电\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003E2.Doze模式下应用程序有什么变化:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E系统试图通过限制应用程序访问网络和CPU密集型服务节省电池;\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E防止应用程序访问网络,推延应用程序的工作,同步,和标准的警报;\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E系统定期提供一个短暂的时间让应用程序完成延迟的工作活动,在这个时间片里,系统将提供维持性窗口应用程序访问网络,运行在等待的同步,工作,和报警等活动。\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003EDoze模式的五种状态,分别如下:\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003EACTIVE\u003C\u002Fb\u003E:手机设备处于激活活动状态\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003EINACTIVE\u003C\u002Fb\u003E:屏幕关闭进入非活动状态\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003EIDLE_PENDING\u003C\u002Fb\u003E:每隔30分钟让App进入等待空闲预备状态\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003EIDLE\u003C\u002Fb\u003E:空闲状态\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003EIDLE_MAINTENANCE\u003C\u002Fb\u003E:处理挂起任务\u003C\u002Fp\u003E\u003Cp\u003E如下图所示,Doze期间提供间隔一小段时间(30s)供应用程序使用网络和处理挂起的活动。\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic3.zhimg.com\u002Fbed980ca737ce4f8b23e71_b.jpg\& data-rawwidth=\&1839\& data-rawheight=\&740\& class=\&origin_image zh-lightbox-thumb\& width=\&1839\& data-original=\&https:\u002F\u002Fpic3.zhimg.com\u002Fbed980ca737ce4f8b23e71_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='1839'%20height='740'&&\u002Fsvg&\& data-rawwidth=\&1839\& data-rawheight=\&740\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&1839\& data-original=\&https:\u002F\u002Fpic3.zhimg.com\u002Fbed980ca737ce4f8b23e71_r.jpg\& data-actualsrc=\&https:\u002F\u002Fpic3.zhimg.com\u002Fbed980ca737ce4f8b23e71_b.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E从这张图我们可以看到,系统进入Doze模式后,系统会隔一段时间处理正在挂起的任务,随着时间推移,后面间隔的时间会越来越长,以此来减少电量消耗。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E3.退出Doze模式(系统退出休眠,所有的应用程序恢复正常活动):\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E用户唤醒装置移动,打开屏幕\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E或者设备连接电源\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003E4.Doze有哪些限制?\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E网络连接会被禁止\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003EWake Lock会被屏蔽\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003EAlarmManager定时任务延迟到下一个maintenance window进行处理,除非使用AlarmManager提供的方法:setAndAllowWhileIdle() 或者setExactAndAllowWhileIdle()\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E系统将不扫描热点WIFI\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E同步工作将被禁止\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E不允许JobScheduler进行任务调度\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003E5.适配Doze模式有什么方法?\u003C\u002Fstrong\u003E\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003EDoze影响到AlarmManager闹钟和定时器管理活动,在Android6.0引入了两个新方法:setAndAllowWhileIdle() 和setExactAndAllowWhileIdle(),调用两个方法可以在Doze模式下让系统响应定时任务\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003EDoze模式下限制了网络的连接,如果应用程序依赖于实时信息,那么这个将影响App的体验。那么你需要使用Google Cloud Messaging (GCM)谷歌云消息(后面详细讲解)\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E\u003Cstrong\u003E6.测试Doze和App Standby模式的方法(Adb命令)\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E测试Doze模式\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E1. 首先确保你的硬件或虚拟设备是Android6.0或更高版本系统;\u003C\u002Fp\u003E\u003Cp\u003E2. 连接设备到开发机上并安装你的app;\u003C\u002Fp\u003E\u003Cp\u003E3. 运行app并让其运行活动;\u003C\u002Fp\u003E\u003Cp\u003E4. 关闭设备的屏幕;\u003C\u002Fp\u003E\u003Cp\u003E5. 运行以下adb命令使系统进入Doze模式:\u003C\u002Fp\u003E\u003Cp\u003E$ adb shell dumpsys battery unplug\u003C\u002Fp\u003E\u003Cp\u003E$ adb shell dumpsys deviceidle step\u003C\u002Fp\u003E\u003Cp\u003E6. 观察你的app表现行为是否有需优化改进的地方。\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E测试App Standby模式\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E步骤1-3同测试Doze模式\u003C\u002Fp\u003E\u003Cp\u003E4. 运行以下adb命令迫使系统进入App Standby模式:\u003C\u002Fp\u003E\u003Cp\u003E$ adb shell dumpsys battery unplug\u003C\u002Fp\u003E\u003Cp\u003E$ adb shell am set-inactive &packageName& true\u003C\u002Fp\u003E\u003Cp\u003E5. 模拟唤醒你的应用程序使用以下命令:\u003C\u002Fp\u003E\u003Cp\u003E$ adb shell am set-inactive &packageName& false\u003C\u002Fp\u003E\u003Cp\u003E$ adb shell am get-inactive &packageName&\u003C\u002Fp\u003E\u003Cp\u003E6. 观察你的App,确保应用程序恢复正常从待机模式过程中,App的通知及其背部活动能达到预期结果。\u003C\u002Fp\u003E\u003Ch3\u003E\u003Cstrong\u003EUnderstanding App Standby\u003C\u002Fstrong\u003E\u003C\u002Fh3\u003E\u003Cp\u003E当用户不触摸使用应用程序一段时间时,该应用程序处于App Standby状态,系统将把该App标志为空闲状态。除非触发以下任意条件,应用程序将退出App Standby状态:\u003C\u002Fp\u003E\u003Cp\u003E1. 用户主动启动该A\u003C\u002Fp\u003E\u003Cp\u003E2. 该App当前有一个前台进程(或包含一个活动的前台服务,或被另一个activity或前台service使用);\u003C\u002Fp\u003E\u003Cp\u003E3. App生成一个用户所能在锁屏或通知托盘看到的Notification, 而当用户设备插入电源时,系统将会释放App的待机状态,允许他们自由的连接网络及其执行未完成的工作和同步。如果设备空闲很长一段时间,系统将允许空闲App一天一次访问网络。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003EDoze和App Standby的区别:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003EDoze模式需要屏幕关闭(通常晚上睡觉或长时间屏幕关闭才会进入),而App Standby不需要屏幕关闭,App进入后台一段时间也会受到连接网络等限制。\u003C\u002Fp\u003E\u003Ch3\u003E\u003Cstrong\u003EUsing GCM to Interact with Your App While the Device is Idle\u003C\u002Fstrong\u003E\u003C\u002Fh3\u003E\u003Cp\u003E\u003Cstrong\u003E1. 什么是GCM?\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003EGoogle Cloud Messaging(GCM)是一个云到设备的服务,可以让你支持实时在云端服务和Android设备上应用程序之间的消息传递。\u003C\u002Fp\u003E\u003Cp\u003EGCM提供了一个持久连接到云端的链接,让所有需要实时消息传递应用程序可以共享此链接。这个共享链接显著优化电池消耗,使其不必让多个应用程序各位维护自己单独的持久链接而使电池迅速耗尽。\u003C\u002Fp\u003E\u003Cp\u003E由于这个原因,官方建议:如果你的应用需要消息传递与后端服务集成,我们强烈建议尽可能的使用GCM,而不是单独维护自己的网络链接。\u003C\u002Fp\u003E\u003Cp\u003EGCM消息拥有高优先级,不影响Doze模式,且不会不影响其他应用程序的状态。这意味着你的应用程序可以使用它们进行通信,同时最大限度地减少电池在整个系统和设备的影响。\u003C\u002Fp\u003E\u003Cp\u003E以下来GCM自官方解释:\u003C\u002Fp\u003E\u003Cp\u003E一个GCM实现包括谷歌连接服务器,在你的环境中通过HTTP或XMPP协议的连接服务器进行交互的应用程序服务器和客户端应用程序。\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic4.zhimg.com\u002F192fce1eceac_b.jpg\& data-rawwidth=\&701\& data-rawheight=\&233\& class=\&origin_image zh-lightbox-thumb\& width=\&701\& data-original=\&https:\u002F\u002Fpic4.zhimg.com\u002F192fce1eceac_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='701'%20height='233'&&\u002Fsvg&\& data-rawwidth=\&701\& data-rawheight=\&233\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&701\& data-original=\&https:\u002F\u002Fpic4.zhimg.com\u002F192fce1eceac_r.jpg\& data-actualsrc=\&https:\u002F\u002Fpic4.zhimg.com\u002F192fce1eceac_b.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E生命周期流程:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E注册启用GCM: 客户端应用程序注册为接收消息。\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003Cli\u003E\u003Cp\u003E发送和接收下行消息:\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E发送一个消息,该应用程序服务器发送信息到客户端应用程序:\u003C\u002Fp\u003E\u003Cp\u003E1.该应用程序服务器发送消息给GCM连接服务器;\u003C\u002Fp\u003E\u003Cp\u003E2.当设备处于脱机状态,该GCM连接服务器入队并存储消息;\u003C\u002Fp\u003E\u003Cp\u003E3.当设备联机时,GCM连接服务器将邮件发送到该设备;\u003C\u002Fp\u003E\u003Cp\u003E4.在设备上,所述客户端应用程序根据该特定平台实现接收该消息。\u003C\u002Fp\u003E\u003Cp\u003E接收消息,客户端应用程序收到一条消息从GCM连接服务器。\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E\u003Cp\u003E发送和接收上游的消息: 如果您使用的是此功能只提供XMPP连接服务器 。\u003C\u002Fp\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cp\u003E发送一个消息,客户端应用程序将消息发送到应用服务器:\u003C\u002Fp\u003E\u003Cp\u003E1.在设备上,客户端应用程序将消息发送到XMPP连接server;\u003C\u002Fp\u003E\u003Cp\u003E2.如果该服务器已断开连接,该XMPP服务器连接入队并存储信息;\u003C\u002Fp\u003E\u003Cp\u003E3.当应用程序服务器重新连接后,XMPP连接服务器将邮件发送到应用程序服务器。\u003C\u002Fp\u003E\u003Cp\u003E接收消息,一个应用服务器从XMPP连接服务器接收邮件,然后执行以下操作:\u003C\u002Fp\u003E\u003Cp\u003E1、解析消息头,以验证客户端应用程序发送的信息;\u003C\u002Fp\u003E\u003Cp\u003E2、发送“确认”的XMPP连接服务器以确认收到该消息;\u003C\u002Fp\u003E\u003Cp\u003E3、任选解析该消息有效载荷,由客户端应用程序所定义的。\u003C\u002Fp\u003E\u003Cp\u003E除了GCM,Android6.0及更高版本还提供了Doze模式白名单列表,通过设置应用程序进入白名单列表可逃脱Doze模式的各种限制。\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cp\u003E检测应用程序是否存在白名单list里面,可使用PowerManager的isIgnoringBatteryOptimizations()方法。\u003C\u002Fp\u003E\u003Cp\u003E用户也可手动设置应用程序进入白名单列表里面,路径为:设置&电池&电池优化白名单:\u003Cbr\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic1.zhimg.com\u002F401c44eac8cdccc46b0522e_b.jpg\& data-rawwidth=\&640\& data-rawheight=\&1144\& class=\&origin_image zh-lightbox-thumb\& width=\&640\& data-original=\&https:\u002F\u002Fpic1.zhimg.com\u002F401c44eac8cdccc46b0522e_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='640'%20height='1144'&&\u002Fsvg&\& data-rawwidth=\&640\& data-rawheight=\&1144\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&640\& data-original=\&https:\u002F\u002Fpic1.zhimg.com\u002F401c44eac8cdccc46b0522e_r.jpg\& data-actualsrc=\&https:\u002F\u002Fpic1.zhimg.com\u002F401c44eac8cdccc46b0522e_b.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic4.zhimg.com\u002Fc18b4ab9a034e8400ecf8a8_b.jpg\& data-rawwidth=\&640\& data-rawheight=\&1137\& class=\&origin_image zh-lightbox-thumb\& width=\&640\& data-original=\&https:\u002F\u002Fpic4.zhimg.com\u002Fc18b4ab9a034e8400ecf8a8_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='640'%20height='1137'&&\u002Fsvg&\& data-rawwidth=\&640\& data-rawheight=\&1137\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&640\& data-original=\&https:\u002F\u002Fpic4.zhimg.com\u002Fc18b4ab9a034e8400ecf8a8_r.jpg\& data-actualsrc=\&https:\u002F\u002Fpic4.zhimg.com\u002Fc18b4ab9a034e8400ecf8a8_b.jpg\&\u003E\u003C\u002Ffigure\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E客户端使用方法:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E1. App程序可发送action为ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS的intent引导用户进入设置界面将应用程序设置进白名单列表里。\u003C\u002Fp\u003E\u003Cp\u003E2. 应用程序还可以使用AREQUEST_IGNORE_BATTERY_OPTIMIZATIONS 权限来触发一个系统对话来让用户添加到白名单里,而无需进入设置界面去设置。\u003C\u002Fp\u003E\u003Cp\u003E当然,官方也提供用户把你的App移除电池优化白名单的选项。这个白名单也会被Android M的另一个新特性 App Standby使用,所以用户只能简单的进行控制,也就是说设备并不会完全相信这个白名单。\u003C\u002Fp\u003E\u003Cp\u003E官方举了一下白名单例子:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic4.zhimg.com\u002Fe4a728e4c_b.jpg\& data-rawwidth=\&673\& data-rawheight=\&426\& class=\&origin_image zh-lightbox-thumb\& width=\&673\& data-original=\&https:\u002F\u002Fpic4.zhimg.com\u002Fe4a728e4c_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='673'%20height='426'&&\u002Fsvg&\& data-rawwidth=\&673\& data-rawheight=\&426\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&673\& data-original=\&https:\u002F\u002Fpic4.zhimg.com\u002Fe4a728e4c_r.jpg\& data-actualsrc=\&https:\u002F\u002Fpic4.zhimg.com\u002Fe4a728e4c_b.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E$ adb shell dumpsys deviceidle whitelist +&packageName&\u003C\u002Fp\u003E\u003Cp\u003E$ adb shell dumpsys deviceidle\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic2.zhimg.com\u002Fb9b49e0fda861f3bff7d7b4_b.jpg\& data-rawwidth=\&828\& data-rawheight=\&219\& class=\&origin_image zh-lightbox-thumb\& width=\&828\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Fb9b49e0fda861f3bff7d7b4_r.jpg\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='828'%20height='219'&&\u002Fsvg&\& data-rawwidth=\&828\& data-rawheight=\&219\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&828\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Fb9b49e0fda861f3bff7d7b4_r.jpg\& data-actualsrc=\&https:\u002F\u002Fpic2.zhimg.com\u002Fb9b49e0fda861f3bff7d7b4_b.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E\u003Cstrong\u003E总结:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003EDoze模式的推出本身是为了减少电池的消耗,且Google希望统一使用GCM来传递消息进行通讯,而对于国内开发来讲,确实带来了很大的麻烦:\u003C\u002Fp\u003E\u003Cp\u003E1. 国内开发的一些消息推送机制(PUSH)将受到影响;\u003C\u002Fp\u003E\u003Cp\u003E2. 若使用GCM,在国内使用GCM延迟高,对于即时通讯产品来说选择还需勇气啊;\u003C\u002Fp\u003E\u003Cp\u003E3. 国内第三方手机厂商如华为、小米、三星,定制的Rom也将使用定制的推送消息机制。这让同一款App如何选择哪种推送机制才能兼容呢?\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E解决方法:\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E1. 用户添加应用程序到电池优化白名单列表;\u003C\u002Fp\u003E\u003Cp\u003E2. 开发者使用Google提供的ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS意图和AREQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限设置以此忽略(推荐);\u003C\u002Fp\u003E\u003Cp\u003E3. 使用Google提供的GCM;\u003C\u002Fp\u003E\u003Cp\u003E4. 通过so绕过Doze模式。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cb\u003E关于Qzone :\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003EQzone 是中国最大的社交网络,是腾讯集团的核心平台之一,目前Qzone的月活跃账户数达到6.68亿,Qzone智能终端月活跃账户数达到5.68亿。从,Qzone见证了国内互联网蓬勃发展的十年,这十年风云变幻,但我们的业务却不断向前发展,也希望更多的朋友能够加入我们,共同迎接互联网和Qzone的下一个十年。\u003C\u002Fp\u003E\u003Cp\u003E欢迎关注我们Qzone终端开发团队的公众号:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\u002Fpic4.zhimg.com\u002Ffab39cd7fb6ca1e3cbad5_b.jpg\& data-rawwidth=\&258\& data-rawheight=\&258\& class=\&content_image\& width=\&258\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='258'%20height='258'&&\u002Fsvg&\& data-rawwidth=\&258\& data-rawheight=\&258\& class=\&content_image lazy\& width=\&258\& data-actualsrc=\&https:\u002F\u002Fpic4.zhimg.com\u002Ffab39cd7fb6ca1e3cbad5_b.jpg\&\u003E\u003C\u002Ffigure\u003E&,&updated&:new Date(&T08:10:25.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:4,&collapsedCount&:0,&likeCount&:97,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\u002Fpic2.zhimg.com\u002Fa2f8b290f_r.jpg&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&reviewers&:[],&topics&:[],&adminClosedComment&:false,&titleImageSize&:{&width&:1037,&height&:499},&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&column&:{&slug&:&magilu&,&name&:&MAGI的专栏&},&tipjarState&:&inactivated&,&annotationAction&:[],&sourceUrl&:&&,&pageCommentsCount&:4,&hasPublishingDraft&:false,&snapshotUrl&:&&,&publishedTime&:&T16:10:25+08:00&,&url&:&\u002Fp\u002F&,&lastestLikers&:[{&bio&:&安卓工程师&,&isFollowing&:false,&hash&:&bf38e48fe7abebb3f850a6&,&uid&:739300,&isOrg&:false,&slug&:&li-hua-long-61-50&,&isFollowed&:false,&description&:&&,&name&:&就叫taki君吧&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fli-hua-long-61-50&,&avatar&:{&id&:&v2-74c0e9dce73beb8e6e3829e&,&template&:&https:\u002F\u002Fpic3.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&勿谓言之不预也!(怠惰中_(:з」∠)_)&,&isFollowing&:false,&hash&:&75cbdea79efbf5&,&uid&:68,&isOrg&:false,&slug&:&ZH8732&,&isFollowed&:false,&description&:&曾想语不惊人死不休,哪知一针见血、见血封喉-_-||&,&name&:&只为心上人&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002FZH8732&,&avatar&:{&id&:&142e0fd29a08c59d8abf074b&,&template&:&https:\u002F\u002Fpic2.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&&,&isFollowing&:false,&hash&:&5ca23f61ea66b0c32d5bb&,&uid&:72,&isOrg&:false,&slug&:&huang-yi-wen&,&isFollowed&:false,&description&:&&,&name&:&黄团团&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fhuang-yi-wen&,&avatar&:{&id&:&v2-c2dcc1d8e096bec9cc05&,&template&:&https:\u002F\u002Fpic4.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&搞视觉的&,&isFollowing&:false,&hash&:&dc5df3b15b7d6ab&,&uid&:909400,&isOrg&:false,&slug&:&yuanfangdada&,&isFollowed&:false,&description&:&有事儿联系:&,&name&:&袁元芳&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fyuanfangdada&,&avatar&:{&id&:&bd18ebe760e1daf69e0dfab&,&template&:&https:\u002F\u002Fpic3.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},{&bio&:&金融、IT、ACG&,&isFollowing&:false,&hash&:&8c643dcd5cf2&,&uid&:640000,&isOrg&:false,&slug&:&gundam-39&,&isFollowed&:false,&description&:&&,&name&:&gundam&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fgundam-39&,&avatar&:{&id&:&v2-4362bdefec&,&template&:&https:\u002F\u002Fpic1.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false}],&summary&:&\u003Cimg src=\&https:\u002F\u002Fpic3.zhimg.com\u002Fbed980ca737ce4f8b23e71_200x112.jpg\& data-rawwidth=\&1839\& data-rawheight=\&740\& class=\&origin_image inline-img zh-lightbox-thumb\& data-original=\&https:\u002F\u002Fpic3.zhimg.com\u002Fbed980ca737ce4f8b23e71_r.jpg\&\u003E作者:timorzheng出品:QQ空间终端开发团队本文首发于QQ空间终端开发团队的官方公众号,任何形式的转载之前必须与本人联系。 \u003Cstrong\u003EOptimizing for Doze and App Standby\u003C\u002Fstrong\u003E1. 从Android6.0开始,Android提供了两种省电延长电池寿命的功能:Doze和App Standby;2. 表…&,&reviewingCommentsCount&:0,&meta&:{&previous&:{&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\u002Fpic3.zhimg.com\u002F50\u002Feee56927f_xl.jpg&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&topics&:[],&adminClosedComment&:false,&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&author&:{&bio&:&个人问题请移步值乎提问&,&isFollowing&:false,&hash&:&ad02ed87e3941cccc6bb1376581badc1&,&uid&:80,&isOrg&:false,&slug&:&m-a-g-i&,&isFollowed&:false,&description&:&聪明的做法可能有一万种,但善良与正确的路只有一条。&,&name&:&MagiLu&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fm-a-g-i&,&avatar&:{&id&:&b3239bbe59ff7749484c&,&template&:&https:\u002F\u002Fpic4.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&column&:{&slug&:&magilu&,&name&:&MAGI的专栏&},&content&:&\u003Cp\u003E作者:johnczchen\u003C\u002Fp\u003E\u003Cp\u003E出品:QQ空间终端开发团队\u003C\u002Fp\u003E\u003Cp\u003E原文发布于QQ空间终端开发团队的官方公众号,任何形式的转载之前必须与本人联系。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Ch3\u003E\u003Cstrong\u003E1.背景\u003C\u002Fstrong\u003E\u003C\u002Fh3\u003E\u003Cp\u003E
当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App、测试、向各个应用市场和渠道换包、提示用户升级、用户下载、覆盖安装。有时候仅仅是为了修改了一行代码,也要付出巨大的成本进行换包和重新发布。\u003C\u002Fp\u003E\u003Cp\u003E
这时候就提出一个问题:\u003Cb\u003E有没有办法以补丁的方式动态修复紧急Bug,不再需要重新发布App,不再需要用户重新下载,覆盖安装?\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E
虽然Android系统并没有提供这个技术,但是很幸运的告诉大家,答案是:\u003Cb\u003E可以,我们QQ空间提出了热补丁动态修复技术来解决以上这些问题。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E2.实际案例\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E
空间Android独立版5.2发布后,收到用户反馈,结合版无法跳转到独立版的访客界面,每天都较大的反馈。在以前只能紧急换包,重新发布。成本非常高,也影响用户的口碑。最终决定使用热补丁动态修复技术,\u003Cb\u003E向用户下发Patch,在用户无感知的情况下,修复了外网问题,取得非常好的效果。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cstrong\u003E3.解决方案\u003C\u002Fstrong\u003E\u003C\u002Fp\u003E\u003Cp\u003E
该方案基于的是android dex分包方案的,关于dex分包方案,网上有几篇解释了,所以这里就不再赘述,具体可以看这里\u003Ca href=\&http:\u002F\u002Flink.zhihu.com\u002F?target=https%3A\u002F\u002Fm.oschina.net\u002Fblog\u002F308583\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003EAndroid dex分包方案\u003C\u002Fa\u003E。\u003C\u002Fp\u003E\u003Cp\u003E
简单的概括一下,就是把多个dex文件塞入到app的classloader之中,但是android dex拆包方案中的类是没有重复的,如果classes.dex和classes1.dex中有重复的类,当用到这个重复的类的时候,系统会选择哪个类进行加载呢?\u003C\u002Fp\u003E\u003Cp\u003E
让我们来看看类加载的代码:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic2.zhimg.com\u002F3de788b45ea45ef_b.jpg\& data-rawwidth=\&640\& data-rawheight=\&697\& class=\&origin_image zh-lightbox-thumb\& width=\&640\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002F3de788b45ea45ef_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E
一个ClassLoader可以包含多个dex文件,每个dex文件是一个Element,多个dex文件排列成一个有序的数组dexElements,当找类的时候,会按顺序遍历dex文件,然后从当前遍历的dex文件中找类,如果找类则返回,如果找不到从下一个dex文件继续查找。\u003C\u002Fp\u003E\u003Cp\u003E
理论上,如果在不同的dex中有相同的类存在,那么会优先选择排在前面的dex文件的类,如下图:\u003C\u002Fp\u003E\u003Cp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic2.zhimg.com\u002Fc3d8d50bdf89d50bf1ccc_b.jpg\& data-rawwidth=\&1190\& data-rawheight=\&523\& class=\&origin_image zh-lightbox-thumb\& width=\&1190\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Fc3d8d50bdf89d50bf1ccc_r.jpg\&\u003E\u003C\u002Ffigure\u003E在此基础上,我们构想了热补丁的方案,把有问题的类打包到一个dex(patch.dex)中去,然后把这个dex插入到Elements的最前面,如下图:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic1.zhimg.com\u002F5af6c469aee_b.jpg\& data-rawwidth=\&1188\& data-rawheight=\&512\& class=\&origin_image zh-lightbox-thumb\& width=\&1188\& data-original=\&https:\u002F\u002Fpic1.zhimg.com\u002F5af6c469aee_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E好,该方案基于第二个拆分dex的方案,方案实现如果懂拆分dex的原理的话,大家应该很快就会实现该方案,如果没有拆分dex的项目的话,可以参考一下谷歌的multidex方案实现。然后在插入数组的时候,把补丁包插入到最前面去。\u003C\u002Fp\u003E\u003Cp\u003E好,看似问题很简单,轻松的搞定了,让我们来试验一下,修改某个类,然后打包成dex,插入到classloader,当加载类的时候出现了(本例中是QzoneActivityManager要被替换):\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic2.zhimg.com\u002Ff08b4e50095ffbbef1837e_b.jpg\& data-rawwidth=\&1266\& data-rawheight=\&559\& class=\&origin_image zh-lightbox-thumb\& width=\&1266\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Ff08b4e50095ffbbef1837e_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E\u003Cb\u003E为什么会出现以上问题呢?\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E
从log的意思上来讲,ModuleManager引用了QzoneActivityManager,但是发现这这两个类所在的dex不在一起,其中:\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E1. ModuleManager在classes.dex中\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E2. QzoneActivityManager在patch.dex中\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E结果发生了错误。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E这里有个问题,拆分dex的很多类都不是在同一个dex内的,怎么没有问题?\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E
让我们搜索一下抛出错误的代码所在,嘿咻嘿咻,找到了一下代码:\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic1.zhimg.com\u002Fe4a58a5c4f9c245f83d637_b.jpg\& data-rawwidth=\&1184\& data-rawheight=\&2868\& class=\&origin_image zh-lightbox-thumb\& width=\&1184\& data-original=\&https:\u002F\u002Fpic1.zhimg.com\u002Fe4a58a5c4f9c245f83d637_r.jpg\&\u003E\u003C\u002Ffigure\u003E
从代码上来看,如果两个相关联的类在不同的dex中就会报错,但是拆分dex没有报错这是为什么,原来这个校验的前提是:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic2.zhimg.com\u002Fe58fc77e685ed857ccfb3_b.jpg\& data-rawwidth=\&640\& data-rawheight=\&112\& class=\&origin_image zh-lightbox-thumb\& width=\&640\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002Fe58fc77e685ed857ccfb3_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E如果引用者(也就是ModuleManager)这个类被打上了\u003Cb\u003ECLASS_ISPREVERIF\u003C\u002Fb\u003E\u003Cb\u003EIED\u003C\u002Fb\u003E标志,那么就会进行dex的校验。那么这个标志是什么时候被打上去的?\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E让我们在继续搜索一下代码,嘿咻嘿咻~~,在DexPrepare.cpp找到了一下代码:\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic1.zhimg.com\u002Fbadd767fccedc6ddcc4a_b.jpg\& data-rawwidth=\&757\& data-rawheight=\&565\& class=\&origin_image zh-lightbox-thumb\& width=\&757\& data-original=\&https:\u002F\u002Fpic1.zhimg.com\u002Fbadd767fccedc6ddcc4a_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E这段代码是dex转化成odex(dexopt)的代码中的一段,我们知道当一个apk在安装的时候,apk中的classes.dex会被虚拟机(dexopt)优化成odex文件,然后才会拿去执行。\u003C\u002Fp\u003E\u003Cp\u003E
虚拟机在启动的时候,会有许多的启动参数,其中一项就是verify选项,当verify选项被打开的时候,上面doVerify变量为true,那么就会执行dvmVerifyClass进行类的校验,如果dvmVerifyClass校验类成功,那么这个类会被打上CLASS_ISPREVERIFIED的标志,那么具体的校验过程是什么样子的呢?\u003C\u002Fp\u003E\u003Cp\u003E
此代码在DexVerify.cpp中,如下:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic2.zhimg.com\u002F979fdb303e4cb2d86c49a_b.jpg\& data-rawwidth=\&892\& data-rawheight=\&454\& class=\&origin_image zh-lightbox-thumb\& width=\&892\& data-original=\&https:\u002F\u002Fpic2.zhimg.com\u002F979fdb303e4cb2d86c49a_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E1. 验证clazz-&directMethods方法,directMethods包含了以下方法:\u003C\u002Fp\u003E\u003Cp\u003E
1. static方法\u003C\u002Fp\u003E\u003Cp\u003E
2. private方法\u003C\u002Fp\u003E\u003Cp\u003E
3. 构造函数\u003C\u002Fp\u003E\u003Cp\u003E2. clazz-&virtualMethods\u003C\u002Fp\u003E\u003Cp\u003E
1. 虚函数=override方法?\u003C\u002Fp\u003E\u003Cp\u003E概括一下就是如果以上方法中直接引用到的类(第一层级关系,不会进行递归搜索)和clazz都在同一个dex中的话,那么这个类就会被打上\u003Cb\u003ECLASS_ISPREVERIFIED\u003C\u002Fb\u003E:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic1.zhimg.com\u002Fe6bb1308ae38ffc0e223e_b.jpg\& data-rawwidth=\&640\& data-rawheight=\&650\& class=\&origin_image zh-lightbox-thumb\& width=\&640\& data-original=\&https:\u002F\u002Fpic1.zhimg.com\u002Fe6bb1308ae38ffc0e223e_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E\u003Cb\u003E所以为了实现补丁方案,所以必须从这些方法中入手,防止类被打上CLASS_ISPREVERIFIED标志。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E最终空间的方案是往所有类的构造函数里面插入了一段代码,代码如下:\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003Eif (ClassVerifier.PREVENT_VERIFY) {\u003C\u002Fp\u003E\u003Cp\u003E
System.out.println(AntilazyLoad.class);\u003C\u002Fp\u003E\u003Cp\u003E}\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E其中AntilazyLoad类会被打包成单独的hack.dex,这样当安装apk的时候,classes.dex内的类都会引用一个在不相同dex中的AntilazyLoad类,这样就防止了类被打上CLASS_ISPREVERIFIED的标志了,只要没被打上这个标志的类都可以进行打补丁操作。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E然后在应用启动的时候加载进来.AntilazyLoad类所在的dex包必须被先加载进来,不然AntilazyLoad类会被标记为不存在,即使后续加载了hack.dex包,那么他也是不存在的,这样屏幕就会出现茫茫多的类AntilazyLoad找不到的log。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E所以Application作为应用的入口不能插入这段代码。(因为载入hack.dex的代码是在Application中onCreate中执行的,如果在Application的构造函数里面插入了这段代码,那么就是在hack.dex加载之前就使用该类,该类一次找不到,会被永远的打上找不到的标志)\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E其中:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic4.zhimg.com\u002F43e5dcd19ab8_b.jpg\& data-rawwidth=\&640\& data-rawheight=\&122\& class=\&origin_image zh-lightbox-thumb\& width=\&640\& data-original=\&https:\u002F\u002Fpic4.zhimg.com\u002F43e5dcd19ab8_r.jpg\&\u003E\u003C\u002Ffigure\u003E\u003Cp\u003E之所以选择构造函数是因为他不增加方法数,一个类即使没有显式的构造函数,也会有一个隐式的默认构造函数。\u003C\u002Fp\u003E\u003Cp\u003E
空间使用的是在字节码插入代码,而不是源代码插入,使用的是javaassist库来进行字节码插入的。\u003C\u002Fp\u003E\u003Ch2\u003E隐患:\u003C\u002Fh2\u003E\u003Cp\u003E
虚拟机在安装期间为类打上\u003Cb\u003ECLASS_ISPREVERIFIED\u003C\u002Fb\u003E标志是为了提高性能的,我们强制防止类被打上标志是否会影响性能?这里我们会做一下更加详细的性能测试.但是在大项目中拆分dex的问题已经比较严重,很多类都没有被打上这个标志。\u003C\u002Fp\u003E\u003Cp\u003E如何打包补丁包:\u003C\u002Fp\u003E\u003Cp\u003E1. 空间在正式版本发布的时候,会生成一份缓存文件,里面记录了所有class文件的md5,还有一份mapping混淆文件。\u003C\u002Fp\u003E\u003Cp\u003E2. 在后续的版本中使用-applymapping选项,应用正式版本的mapping文件,然后计算编译完成后的class文件的md5和正式版本进行比较,把不相同的class文件打包成补丁包。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E备注:该方案现在也应用到我们的编译过程当中,编译不需要重新打包dex,只需要把修改过的类的class文件打包成patch dex,然后放到sdcard下,那么就会让改变的代码生效。\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cb\u003E关于Qzone :\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003EQzone 是中国最大的社交网络,是腾讯集团的核心平台之一,目前Qzone的月活跃账户数达到6.68亿,Qzone智能终端月活跃账户数达到5.68亿。从,Qzone见证了国内互联网蓬勃发展的十年,这十年风云变幻,但我们的业务却不断向前发展,也希望更多的朋友能够加入我们,共同迎接互联网和Qzone的下一个十年。\u003C\u002Fp\u003E\u003Cp\u003E欢迎关注我们Qzone终端开发团队的公众号:\u003C\u002Fp\u003E\u003Cfigure\u003E\u003Cimg src=\&https:\u002F\u002Fpic4.zhimg.com\u002Ffab39cd7fb6ca1e3cbad5_b.jpg\& data-rawwidth=\&258\& data-rawheight=\&258\& class=\&content_image\& width=\&258\&\u003E\u003C\u002Ffigure\u003E&,&state&:&published&,&sourceUrl&:&&,&pageCommentsCount&:0,&canComment&:false,&snapshotUrl&:&&,&slug&:,&publishedTime&:&T15:31:44+08:00&,&url&:&\u002Fp\u002F&,&title&:&安卓App热补丁动态修复技术介绍&,&summary&:&作者:johnczchen出品:QQ空间终端开发团队原文发布于QQ空间终端开发团队的官方公众号,任何形式的转载之前必须与本人联系。 \u003Cstrong\u003E1.背景\u003C\u002Fstrong\u003E 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App、测试、向各…&,&reviewingCommentsCount&:0,&meta&:{&previous&:null,&next&:null},&commentPermission&:&anyone&,&commentsCount&:23,&likesCount&:226},&next&:{&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&https:\u002F\u002Fpic3.zhimg.com\u002F50\u002Fec0a2abd624a64cbb2232e2_xl.jpg&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&topics&:[],&adminClosedComment&:false,&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&author&:{&bio&:&个人问题请移步值乎提问&,&isFollowing&:false,&hash&:&ad02ed87e3941cccc6bb1376581badc1&,&uid&:80,&isOrg&:false,&slug&:&m-a-g-i&,&isFollowed&:false,&description&:&聪明的做法可能有一万种,但善良与正确的路只有一条。&,&name&:&MagiLu&,&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fm-a-g-i&,&avatar&:{&id&:&b3239bbe59ff7749484c&,&template&:&https:\u002F\u002Fpic4.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false},&column&:{&slug&:&magilu&,&name&:&MAGI的专栏&},&content&:&\u003Cp\u003E我一直认为具备独立思考能力的重要性超越其它技能,如果说我真的有什么擅长的东西,可能就是思考。但有非常多的东西超出我目前的知识范围,思考也并不是闭门造车,我相信与有价值的人对话可以使我思考的更深更广。同时,我也愿意把中间对话的过程记录下来于大家共享,因此开了这个【TALK】系列。\u003C\u002Fp\u003E\u003Cp\u003E这个系列主题围绕着移动开发,开发者,互联网行业以及相关的一些热点。而对话的人,主要是行业内的中坚开发者。本着深一度,慢一步的理念,我会在充分了解对方背景的基础上与其沟通一系列我认为有价值的问题。\u003C\u002Fp\u003E\u003Cp\u003E【TALK】系列的第一期文章是【Talk With Reyd】,同时感谢 \u003Ca href=\&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fc675a876b8ce192aa38e976\& data-hash=\&c675a876b8ce192aa38e976\& class=\&member_mention\& data-editable=\&true\& data-title=\&@肥肥鱼\& data-tip=\&p$b$c675a876b8ce192aa38e976\& data-hovercard=\&p$b$c675a876b8ce192aa38e976\&\u003E@肥肥鱼\u003C\u002Fa\u003E 对本系列文章提出的建议,但最近工作实在太忙,估计会无限期拖稿。\u003C\u002Fp\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cb\u003EThe last but the most important:\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E欢迎 \u003Ca href=\&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002F54a10bc8c8bdff89f7db\& data-hash=\&54a10bc8c8bdff89f7db\& class=\&member_mention\& data-editable=\&true\& data-title=\&@RxRead\& data-tip=\&p$b$54a10bc8c8bdff89f7db\& data-hovercard=\&p$b$54a10bc8c8bdff89f7db\&\u003E@RxRead\u003C\u002Fa\u003E 加入Qzone终端开发团队,Qzone的下一个十年,感谢有你。\u003C\u002Fp\u003E&,&state&:&published&,&sourceUrl&:&&,&pageCommentsCount&:0,&canComment&:false,&snapshotUrl&:&&,&slug&:,&publishedTime&:&T18:14:10+08:00&,&url&:&\u002Fp\u002F&,&title&:&【TALK】系列文章预告&,&summary&:&我一直认为具备独立思考能力的重要性超越其它技能,如果说我真的有什么擅长的东西,可能就是思考。但有非常多的东西超出我目前的知识范围,思考也并不是闭门造车,我相信与有价值的人对话可以使我思考的更深更广。同时,我也愿意把中间对话的过程记录下来于…&,&reviewingCommentsCount&:0,&meta&:{&previous&:null,&next&:null},&commentPermission&:&anyone&,&commentsCount&:6,&likesCount&:19}},&annotationDetail&:null,&commentsCount&:4,&likesCount&:97,&FULLINFO&:true}},&User&:{&m-a-g-i&:{&isFollowed&:false,&name&:&MagiLu&,&headline&:&聪明的做法可能有一万种,但善良与正确的路只有一条。&,&avatarUrl&:&https:\u002F\u002Fpic4.zhimg.com\u002Fb3239bbe59ff7749484c_s.jpg&,&isFollowing&:false,&type&:&people&,&slug&:&m-a-g-i&,&bio&:&个人问题请移步值乎提问&,&hash&:&ad02ed87e3941cccc6bb1376581badc1&,&uid&:80,&isOrg&:false,&description&:&聪明的做法可能有一万种,但善良与正确的路只有一条。&,&badge&:{&identity&:null,&bestAnswerer&:{&topics&:[{&type&:&topic&,&id&:&&,&name&:&Android 开发&}],&description&:&优秀回答者&}},&profileUrl&:&https:\u002F\u002Fwww.zhihu.com\u002Fpeople\u002Fm-a-g-i&,&avatar&:{&id&:&b3239bbe59ff7749484c&,&template&:&https:\u002F\u002Fpic4.zhimg.com\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false,&isBanned&:false}},&Comment&:{},&favlists&:{}},&me&:{},&global&:{&experimentFeatures&:{&ge3&:&ge3_9&,&ge2&:&ge2_1&,&androidPassThroughPush&:&all&,&sEI&:&c&,&nwebQAGrowth&:&experiment&,&qawebRelatedReadingsContentControl&:&close&,&liveStore&:&ls_a2_b2_c1_f2&,&qawebThumbnailAbtest&:&new&,&nwebSearch&:&nweb_search_heifetz&,&rt&:&y&,&showVideoUploadAttention&:&true&,&isOffice&:&false&,&enableTtsPlay&:&post&,&newQuestionDiversion&:&https:\u002F\u002Fzhuanlan.zhihu.com\u002Fp\u002F&,&newLiveFeedMediacard&:&new&,&newMobileAppHeader&:&true&,&hybridZhmoreVideo&:&yes&,&nwebGrowthPeople&:&default&,&nwebSearchSuggest&:&default&,&qrcodeLogin&:&qrcode&,&enableVoteDownReasonMenu&:&enable&,&isf8&:&1&,&isShowUnicomFreeEntry&:&unicom_free_entry_off&,&newMobileColumnAppheader&:&new_header&,&androidDbRecommendAction&:&open&,&zcmLighting&:&zcm&,&androidDbFeedHashTagStyle&:&button&,&appStoreRateDialog&:&close&,&default&:&None&,&isNewNotiPanel&:&no&,&wechatShareModal&:&wechat_share_modal_show&,&growthBanner&:&default&,&androidProfilePanel&:&panel_b&}},&columns&:{&next&:{},&magilu&:{&following&:false,&canManage&:false,&href&:&\u002Fapi\u002Fcolumns\u002Fmagilu&,&name&:&MAGI的专栏&,&creator&:{&slug&:&m-a-g-i&},&url&:&\u002Fmagilu&,&slug&:&magilu&,&avatar&:{&id&:&a23ac5d2dcbc4459&,&template&:&https:\u002F\u002Fpic1.zhimg.com\u002F{id}_{size}.jpg&}}},&columnPosts&:{},&columnSettings&:{&colomnAuthor&:[],&uploadAvatarDetails&:&&,&contributeRequests&:[],&contributeRequestsTotalCount&:0,&inviteAuthor&:&&},&postComments&:{},&postReviewComments&:{&comments&:[],&newComments&:[],&hasMore&:true},&favlistsByUser&:{},&favlistRelations&:{},&promotions&:{},&switches&:{&couldSetPoster&:false},&draft&:{&titleImage&:&&,&titleImageSize&:{},&isTitleImageFullScreen&:false,&canTitleImageFullScreen&:false,&title&:&&,&titleImageUploading&:false,&error&:&&,&content&:&&,&draftLoading&:false,&globalLoading&:false,&pendingVideo&:{&resource&:null,&error&:null}},&drafts&:{&draftsList&:[],&next&:{}},&config&:{&userNotBindPhoneTipString&:{}},&recommendPosts&:{&articleRecommendations&:[],&columnRecommendations&:[]},&env&:{&edition&:{&baidu&:false,&yidianzixun&:false,&qqnews&:false},&isAppView&:false,&appViewConfig&:{&content_padding_top&:128,&content_padding_bottom&:56,&content_padding_left&:16,&content_padding_right&:16,&title_font_size&:22,&body_font_size&:16,&is_dark_theme&:false,&can_auto_load_image&:true,&app_info&:&OS=iOS&},&isApp&:false,&userAgent&:{&ua&:&Mozilla\u002F5.0 (compatible, MSIE 11, Windows NT 6.3; Trident\u002F7.0; rv:11.0) like Gecko&,&browser&:{&name&:&IE&,&version&:&11&,&major&:&11&},&engine&:{&version&:&7.0&,&name&:&Trident&},&os&:{&name&:&Windows&,&version&:&8.1&},&device&:{},&cpu&:{}}},&message&:{&newCount&:0},&pushNotification&:{&newCount&:0}}}

我要回帖

更多关于 脱机状态下网页不可用 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信