实践 Android 7.1 快捷方式新模式

@fython  November 3, 2016

<p class="cjk"><span lang="zh-CN">对于国内的一些 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Android </span></span><span lang="zh-CN">用户而言,可能对快捷方式的认识只是停留在让国产流氓应用偷偷添加推广链接,常常忽略方便好用的被动式快捷方式(通常在 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Launcher </span></span><span lang="zh-CN">中添加小部件可以找到)。</span></p>
<p class="cjk"><span lang="zh-CN">到了 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Android 7.1</span></span><span lang="zh-CN">,</span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Google </span></span><span lang="zh-CN">重新重视快捷方式这一项功能,专门添加了一个新的模式。在已适配过特性的 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Launcher </span></span><span lang="zh-CN">上(如 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Pixel Launcher</span></span><span lang="zh-CN">、</span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Google Now Launcher </span></span><span lang="zh-CN">和 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Nova Launcher</span></span><span lang="zh-CN">),用户长按桌面上的 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">App </span></span><span lang="zh-CN">图标即可显示出开发者准备好的快捷方式。</span></p>

<p class="cjk">1</p>
<p class="cjk"><span lang="zh-CN">对快捷方式的作用理解有很多,我们尽可能只把最需要或是最便捷的动作放上来,就如 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Google </span></span><span lang="zh-CN">官方文档 所说的:</span></p>

  • <p class="cjk"><span lang="zh-CN">在地图应用中导航用户到一个特定的地点</span></p>
  • <p class="cjk"><span lang="zh-CN">在通讯应用中发送信息给一位朋友</span></p>
  • <p class="cjk"><span lang="zh-CN">在媒体应用中播放下一集电视节目</span></p>
  • <p class="cjk"><span lang="zh-CN">在游戏中读取上一个存档点</span></p>

<p class="cjk"><span lang="zh-CN">这些动作除了可以在资源文件中预先编写为静态的快捷方式,然后在运行时进行修改;还可以在运行时通过 </span><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">ShortcutManager API </span></span><span lang="zh-CN">推送、编辑、删除动态的快捷方式。官方文档所述一个应用最多推送五个快捷方式(包括静态和动态的快捷方式),用户可以将快捷方式固定到桌面,但应用无法删除那些已固定的快捷方式,只能禁用它们。</span></p>

<h1 class="cjk">静态快捷方式?</h1>
<p class="cjk">静态快捷方式,即是在 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">AndroidManifest </span></span>和资源文件预先声明的一种快捷方式,除了受 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Android 7.1 </span></span>支持,还可以兼容低版本(当然了,都需要 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Launcher </span></span>配合)。一般用作常用功能的固定入口(如新建信息、设置闹钟、显示用户一天的活动之类),也可以在后续代码中通过 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">ShortcutManager </span></span>修改。</p>
<p class="cjk">添加方法:</p>

  1. <p class="cjk">首先要定位到 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">AndroidManifest.xml </span></span>作为启动入口的 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Activity</span></span>。(<span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Intent Filters </span></span>添加了 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">android.intent.action.MAIN </span></span>动作和 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">android.intent.category.LAUNCHER </span></span>分类的 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Activity</span></span>)。</p>
  2. <p class="cjk">参照以下的代码,在 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US"><meta-data> </span></span>元素中加入快捷方式的定义:</p>
    <span class="tag"><manifest</span> <span class="atn">xmlns:android</span><span class="pun">=</span><span class="atv">"http://schemas.android.com/apk/res/android"</span><span class="pln">
                 </span><span class="atn">package</span><span class="pun">=</span><span class="atv">"com.example.myapplication"</span><span class="tag">></span><span class="pln">
      </span><span class="tag"><application</span><span class="pln"> ... </span><span class="tag">></span><span class="pln">
        </span><span class="tag"><activity</span> <span class="atn">android:name</span><span class="pun">=</span><span class="atv">"Main"</span><span class="tag">></span><span class="pln">
          </span><span class="tag"><intent-filter></span><span class="pln">
            </span><span class="tag"><action</span> <span class="atn">android:name</span><span class="pun">=</span><span class="atv">"android.intent.action.MAIN"</span> <span class="tag">/></span><span class="pln">
            </span><span class="tag"><category</span> <span class="atn">android:name</span><span class="pun">=</span><span class="atv">"android.intent.category.LAUNCHER"</span> <span class="tag">/></span><span class="pln">
          </span><span class="tag"></intent-filter></span><span class="pln">
          </span><span class="tag"><meta-data</span> <span class="atn">android:name</span><span class="pun">=</span><span class="atv">"android.app.shortcuts"</span><span class="pln">
                     </span><span class="atn">android:resource</span><span class="pun">=</span><span class="atv">"@xml/shortcuts"</span> <span class="tag">/></span><span class="pln">
        </span><span class="tag"></activity></span><span class="pln">
      </span><span class="tag"></application></span>
    <span class="tag"></manifest></span>

    </li>

    <li>

    <p class="cjk">在 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">/res/xml </span></span>创建一个新的资源文件 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">(</span></span>例如 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">shortcuts.xml) </span></span>作为快捷方式的定义。</p>
    </li>

    <li>

    <p class="cjk">在这个新的资源文件中以 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US"><shortcuts> </span></span>作为根 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">element</span></span>,其中包含若干个 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US"><shortcut> </span></span>元素,记录着各个快捷方式的图标、标签、长标题以及启动 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Intents:</span></span></p>

    <?xml version="1.0" encoding="utf-8"?>
    <shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    
       <shortcut
          android:shortcutId="favorites"
          android:enabled="true"
          android:icon="@drawable/ic_shortcut_favourite"
          android:shortcutShortLabel="@string/label_favourites_shortcut"
          android:shortcutLongLabel="@string/label_favourites_shortcut_long">
          <intent
             android:action="android.intent.action.VIEW"
             android:targetPackage="com.sspai.cuto.android"
             android:targetClass="com.sspai.cuto.android.ui.FavouritesActivity" />
          <categories android:name="android.shortcut.conversation" />
       </shortcut>
       <!-- 这里可以定义更多的快捷方式 -->
    
    </shortcuts>

    </li>

    <li>

    <p class="cjk">到这里就完成了静态快捷方式的定义了,效果如图(此处用了第三方的 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Launcher </span></span>显示,会额外显示一个 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Icon options</span></span>,暂且不管):</p>
    </li>
    </ol>
    <p class="cjk">2</p>

    <h1 class="cjk">动态快捷方式?</h1>
    <p class="cjk">动态快捷方式,即是应用在运行时通过 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">ShortcutManager </span></span>进行动态添加的快捷方式,和以前所认识的“快捷方式”不同,它并不会直接丢到桌面而是像静态快捷方式一样显示在一个菜单中,一般只用于上下文相关的特定操作(比如常用联系人、订阅的节目之类会在应用使用过程中不断变化的数据)。这种快捷方式依赖于 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Android 7.1 </span></span>的新 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">API</span></span>,无法在低版本使用,这点需要注意。(期待 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Google </span></span>推出相应的兼容库)</p>
    <p class="cjk"><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">ShortcutManager API </span></span>允许你进行下列操作:</p>

    • <p class="cjk">推送:使用 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">setDynamicShortcuts(List) </span></span>来重新设置动态快捷方式的列表,或者使用 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">addDynamicShortcuts(List) </span></span>来添加到已存在的快捷方式列表。</p>
    • <p class="cjk">更新:使用 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">updateShortcuts(List)</span></span></p>
    • <p class="cjk">移除:使用 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">removeDynamicShortcuts(List) </span></span>来移除一些快捷方式,或者通过 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">removeAllDynamicShortcuts() </span></span>移除全部快捷方式。</p>

    <p class="cjk">下面的代码片段就是创建一个动态快捷方式并添加到你的应用中:</p>

    <span class="typ">ShortcutManager</span><span class="pln"> shortcutManager </span><span class="pun">=</span><span class="pln"> getSystemService</span><span class="pun">(</span><span class="typ">ShortcutManager</span><span class="pun">.</span><span class="kwd">class</span><span class="pun">);</span>
    
    <span class="typ">ShortcutInfo</span><span class="pln"> shortcut </span><span class="pun">=</span> <span class="kwd">new</span> <span class="typ">ShortcutInfo</span><span class="pun">.</span><span class="typ">Builder</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span> <span class="str">"id1"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">setShortLabel</span><span class="pun">(</span><span class="str">"Web site"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">setLongLabel</span><span class="pun">(</span><span class="str">"Open the web site"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">setIcon</span><span class="pun">(</span><span class="typ">Icon</span><span class="pun">.</span><span class="pln">createWithResource</span><span class="pun">(</span><span class="pln">context</span><span class="pun">,</span><span class="pln"> R</span><span class="pun">.</span><span class="pln">drawable</span><span class="pun">.</span><span class="pln">icon_website</span><span class="pun">))</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">setIntent</span><span class="pun">(</span><span class="kwd">new</span> <span class="typ">Intent</span><span class="pun">(</span><span class="typ">Intent</span><span class="pun">.</span><span class="pln">ACTION_VIEW</span><span class="pun">,</span><span class="pln">
                       </span><span class="typ">Uri</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span class="str">"https://www.mysite.example.com/"</span><span class="pun">)))</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">build</span><span class="pun">();</span><span class="pln">
    
    shortcutManager</span><span class="pun">.</span><span class="pln">setDynamicShortcuts</span><span class="pun">(</span><span class="typ">Arrays</span><span class="pun">.</span><span class="pln">asList</span><span class="pun">(</span><span class="pln">shortcut</span><span class="pun">));</span>

    <h1 class="cjk">快捷方式的图标设计</h1>
    <p class="cjk">为了和 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Android </span></span>系统、其他应用的风格一致,应当按照 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Material Design Guideline </span></span>中的介绍设计,但我阅读过程没有找到相关的资料,可能是刚刚推出新特性尚未跟进设计文档。</p>
    <p class="cjk">参考 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Google </span></span>全家桶的应用后,在此提供个人总结的一些观点:</p>

    • <p class="cjk">圆形底板:我想这个不用多说吧。</p>
    • <p class="cjk">无阴影:快捷方式菜单中图标应和文本处于同一层面,而固定到桌面的快捷方式图标会由 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Launcher </span></span>自动添加上一层阴影。</p>
    • <p class="cjk">色调一致:尽量统一使用产品的主色调(当图标 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Symbol </span></span>使用主色调时,背景使用 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">Grey 100</span></span>:<span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">#F5F5F5</span></span>)</p>

     
    <p class="cjk">在此我提供 Cuto 中的一个样例和 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">PSD </span></span>模版供大家参考:</p>
    <p class="cjk">ic_shortcut_shuffle_xxxhdpi</p>
    <p class="cjk"><span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">PSD </span></span>和<span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">PNG</span></span>:<span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">https://pan.baidu.com/s/1nuOlcpz</span></span></p>

    <h1 class="cjk">快捷方式的最佳实践</h1>

    • <p class="cjk">只添加四个以内不同的快捷方式</p> <p class="cjk">尽管接口允许添加五个静态或动态快捷方式,但还是应当只添加四个以内,这样看上去会更加的整洁。</p>
    • <p class="cjk">限制快捷方式的描述文本长度</p> <p class="cjk">快捷方式菜单的显示空间很有限,短的描述应该控制在 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">10 </span></span>个半角字符,而长描述应该控制在 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">25 </span></span>个半角字符内。</p>
    • <p class="cjk">动态快捷方式不会随着手机数据备份还原</p> <p class="cjk">它并不会在备份还原的过程中保留,因此建议你在每次运行应用的时候通过 <span style="font-family: 'Liberation Serif', serif;"><span lang="en-US">getDynamicShortcuts() </span></span>来检查项目数量并在必要时重新添加快捷方式,例如以下代码片段:</p>
      <span class="kwd">public</span> <span class="kwd">class</span> <span class="typ">MainActivity</span> <span class="kwd">extends</span> <span class="typ">Activity</span> <span class="pun">{</span><span class="pln">
          </span><span class="kwd">public</span> <span class="kwd">void</span><span class="pln"> onCreate</span><span class="pun">(</span><span class="typ">Bundle</span><span class="pln"> savedInstanceState</span><span class="pun">)</span> <span class="pun">{</span><span class="pln">
              </span><span class="kwd">super</span><span class="pun">.</span><span class="pln">onCreate</span><span class="pun">(</span><span class="pln">savedInstanceState</span><span class="pun">);</span><span class="pln">
              </span><span class="typ">ShortcutManager</span><span class="pln"> shortcutManager </span><span class="pun">=</span><span class="pln">
                      getSystemService</span><span class="pun">(</span><span class="typ">ShortcutManager</span><span class="pun">.</span><span class="kwd">class</span><span class="pun">);</span><span class="pln">
      
              </span><span class="kwd">if</span> <span class="pun">(</span><span class="pln">shortcutManager</span><span class="pun">.</span><span class="pln">getDynamicShortcuts</span><span class="pun">().</span><span class="pln">size</span><span class="pun">()</span> <span class="pun">==</span> <span class="lit">0</span><span class="pun">)</span> <span class="pun">{</span><span class="pln">
                  </span><span class="com">// Application restored. Need to re-publish dynamic shortcuts.</span><span class="pln">
                  </span><span class="kwd">if</span> <span class="pun">(</span><span class="pln">shortcutManager</span><span class="pun">.</span><span class="pln">getPinnedShortcuts</span><span class="pun">().</span><span class="pln">size</span><span class="pun">()</span> <span class="pun">></span> <span class="lit">0</span><span class="pun">)</span> <span class="pun">{</span><span class="pln">
                      </span><span class="com">// Pinned shortcuts have been restored. Use</span><span class="pln">
                      </span><span class="com">// updateShortcuts(List) to make sure they</span><span class="pln">
                      </span><span class="com">// contain up-to-date information.</span><span class="pln">
                  </span><span class="pun">}</span><span class="pln">
              </span><span class="pun">}</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
          </span><span class="com">// ...</span>
      <span class="pun">}</span><span class="pln">
          </span>

      </li>
      </ul>
      <h1>More....</h1>
      还有一些不重要的内容在这里没有提及,想深入学习请点击 https://developer.android.com/preview/shortcuts.html 并多实践。


添加新评论