Android M发布有一段时间了,AndroidM在API上的改动,并不比AndroidL小。我们只能感谢Google又给android程序员带来的新的研究课题,以前开发的程序如何才能在AndroidM上顺利运行,因此,让无所事事的程序又要折腾一阵子了。
动态权限请求是Google在对Android的安全问题进行一次非常有效的提升,对用户是非常有用的,用户可以很任性的关掉App一些权限,比如打电话,发短信。然而,对Android程序员来说,却是非常致命,曾经天经地义可以使用的API尽然会抛异常导致程序crash了。这让我们的代码逻辑完全不适用了。
要搞清这事儿,得先从Android 权限定义的变动说起。
首先Google把Android的权限分为了两类,一类叫正常权限(Normal Permission),另一类叫危险权限(Dangerous Permisson )。
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_ WIFI_STATE BLUETOOTH
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
FLASHLIGHT
GET_PACKAGE_SIZE INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_TIME_ZONE SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR USE_FINGERPRINT
VIBRATE WAKE_LOCK
WRITE_SYNC_SETTINGS
SET_ALARM INSTALL_SHORTCUT
UNINSTALL_SHORTCUT
危险权限:当应用程序需要访问用户的个人数据,或是影响用户已保存的数据时发生的权限。当使用这类权限时,那就必须显式的让用户同意(iOS也是这么做的)。危险权限本身是分组的,每一组之内的权限只需要申明一次。
比如上表中ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION是同属于LOCATION这个权限组,那么只要在申请ACCESS_FINE_LOCATION时,用户同意了,则系统自动会赋与ACCESS_COARSE_LOCATION的权限,不需要重新申请了。
如果用户运行手机在Android 5.1以下(含),或者是编译时targetSDK在22以下(含), 那么你当然需要把所有用到的权限放到manifest中,用户一旦安装时同意了权限,你的程序就有了所有权限,如果用户不同意,则无法安装(我们一直就是这么做的,就不废话了)。
如果用户的设备是在Android 6以上,并且编译时的targetSDK不幸被Wizard自动赋予到23以上,那恭喜你,中奖了。你就需要在使用危险权限的时候,向用户说明申请,就不能偷偷的在后面打枪了。
在使用危险权限的时候,首先检查自己当前是否具有权限。在v4包中有个类可以使用。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">int permissionCheck = ContextCompat<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.checkSelfPermission</span>(context, Manifest<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.permission</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SEND</span>_SMS)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
当有权限时,返回PackageManager.PERMISSION_GRANTED,没有权限时,返回PackageManager.PERMISSION_DENIED。如果返回后者,那么就需要申请权限了。
在弹出权限申请对话框(系统对话框)之前,推荐的做法是在某些情况下先简单解释下为什么我需要这个权限,当然这个解释不能太罗嗦,要言简意赅。比如在使用美图秀秀时,告诉用户我要使用camera权限,用户都能很好理解。在support包中有个工具,
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">ActivityCompat<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.shouldShowRequestPermissionRationale</span>(context, Manifest<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.permission</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SEND</span>_SMS)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
当第一次请求或是用户关闭了这个权限时,返回true,其他情况下返回False,当然sdk 23以下的手机总是返回false.
如果收到true, 那么你需要提示用户你为什么需要权限。
当你确定你需要申请权限(在检查权限方法返回PERMISSION_DENIED),你就可以调用申请权限的api。这个API支持批量申请,但是不建议一次申请太多,一般都是用到什么权限申请什么权限,因为用户需要对每一个权限做确认。
这个API也是在ActivityCompat中,他的函数签名是这样的。
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">requestPermissions(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@NonNull</span> Activity activity, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@NonNull</span> String[] permissions, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> requestCode)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
第二个参数是要申请的权限列表,第三个参数很眼熟吧,requestCode,你猜对了,就像是startActivityForResult中的requestCode一样,这个是用来处理回调的。
回调方法是:
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults)
注意当你开始使用ActivityCompat时,你Activity的基类就需要是ActivityCompat或是它的子类
这个方法的参数中requestCode用于对应你之前requestPermission中的值,grantResults中的结果与permissions中的权限按顺序一一对应。grantResults的结果是PackageManager.PERMISSION_GRANTED或PackageManager.PERMISSION_DENIED之一。
<code class="hljs javascript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//首先,这段代码运行在继承了ActivityCompat的Activity中。</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (ContextCompat.checkSelfPermission(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//检查是不是要给用户解释为什么?</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (ActivityCompat.shouldShowRequestPermissionRationale(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, Manifest.permission.READ_CONTACTS)) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//做点什么,弹个Toast或是SnackBar吧</span> } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//请求权限</span> ActivityCompat.requestPermissions(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">String</span>[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onRequestPermissionsResult</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> requestCode, String permissions[], <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>[] grantResults) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">switch</span> (requestCode) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">case</span> MY_PERMISSIONS_REQUEST_READ_CONTACTS: { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//如果用户取消,permissions可能为null.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (grantResults.length > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && grantResults[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] == PackageManager.PERMISSION_GRANTED) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 可以安全的调用api。</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 洗洗睡吧,没戏了。</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>
要模拟用户的实际操作以及一些额外的情况,和测试每一个权限的开启和关闭,可以借助adb工具来完成。
按组列出权限
<code class="hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">$ adb shell pm <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">list</span> permissions <span class="hljs-attribute" style="box-sizing: border-box;">-d</span> <span class="hljs-attribute" style="box-sizing: border-box;">-g</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
开启或禁用某个权限
<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">$ adb shell pm [<span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">grant</span>|<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">revoke</span>] PACKAGE <permission-name> </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
如:pm revoke com.win16.recyclerviewdemo android.permission.RECORD_AUDIO
或:pm grant com.win16.recyclerviewdemo android.permission.RECORD_AUDIO
如果你的应用程序权限太多,不太清楚哪些是危险权限需要特别处理,那么可以使用这个python脚本进行检查。
https://github.com/hotchemi/m-permissions-checker
使用方法:
<code class="language-sh hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">$ cd <root your app> $ python permissions_checker<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.py</span> > Searching file: /Users/hoge/test/data/AndroidManifest<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.xml</span> > Unfortunately, you have to handle these permissions <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> MNC. > android<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.permission</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.READ</span>_CALENDAR > android<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.permission</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.WRITE</span>_CALENDAR > android<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.permission</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.CAMERA</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
在Android M中,Google已经删除了apache的http相应的包,如果你还是想继续使用,那么需要在gradle脚本中加入这一段,
<code class="hljs matlab has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">android <span class="hljs-cell" style="box-sizing: border-box;">{ useLibrary <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'org.apache.http.legacy'</span> }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
但是,最好还是使用HttpURLConnection。这个API更加的高效,有透明的压缩功能和响应缓存,能耗也更低。
如果觉得这个比较原始,也可以使用okHttp库,这个库封装了网络的请求流程,使用也非常方便。
从Android M起,引入了两种新的省电模式,Doze 和 App Standby。当手机没有插电源的时候,如果一段时间内应用程序没有与用户交互,则进入了App Standby模式,此时后台的网络活动会被延迟,如果有很长时间手机都没有使用手机,手机也是关屏状态,则会进入了Doze模式,此时包括CPU的任务和网络都有一定延迟。
前面说到,为了省电,在Doze模式下,应用的网络活动,CPU使用,甚至包括同步功能,和标准Alarm都统统被干掉了。但是,Google也知道,事情不能做得太绝,于是每隔一段时间,就会把应用程序喊起来干活(maintainance Window),处理事情后,又接着睡。再次进入Doze模式。干活的间隔也是越来越久,慢慢衰减。
在Doze模式下,以下活动会被推迟。
推荐情况下,不要修改任何代码,以加强用户手机的续航能力,但是通常产品经理都特别,总会有点特别的要求,那要怎么满足呢。Android实际上也为我们留了点后门。
AlarmManager中新引入了两个方法setAndAllowWhileIdle()或setExactAndAllowWhileIdle()能够在Doze模式下唤醒手机并工作,但是这个技能是有冷却时间的,每15分钟内只能使用一次。
如果对实时性有要求,Google推荐使用GCM….对此,中国开发者只能翻白眼。
Standby模式只限制后台程序,对于前台的程序不限制,而前台程序的定义如下 :
当插上电时,standby模式自动取消,各应用程序可自由活动,想干什么干什么。
当然,很可能应用会有一些特殊的需求,通过GCM还是没能满足。这个时候,就可以使用后门模式,(白名单),你可以在应用中使用带有ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS的Intent向用户进行请求,要求用户把你加到白名单中,这样,这个应用就可以豁免部分Doze模式的限制。注意,这是部分,毕竟是走的后门,不能为所欲为。在白名单中的应用可以使用网络,也可以使用PARTIAL_WAKE_LOCK这个WAKELOCK, 但是,像同步,任务调度,甚至普通的Alarm都还是不能使用。你可以使用PowerManagerr的isIgnoringBatteryOptimizations方法来检查你是不是在白名单中。
要模拟进入Doze模式,可以在关屏下使用以下adb命令:
<code class="hljs ruby has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ </span>adb shell dumpsys battery unplug <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ </span>adb shell dumpsys deviceidle step</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
对于第二条命令要多次使用,直接进入Doze模式。
模拟Standby模式,使用以下Adb命令。
<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">$ adb <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">shell</span> dumpsys battery unplug $ adb <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">shell</span> am <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">set</span>-inactive <packageName> <span class="hljs-constant" style="box-sizing: border-box;">true</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
唤醒使用以下命令
<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">$ adb <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">shell</span> am <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">set</span>-inactive <packageName> <span class="hljs-constant" style="box-sizing: border-box;">false</span> $ adb <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">shell</span> am <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">get</span>-inactive <packageName></code>