[原]Clipboard还能玩出花

lusarder 8年前
   <p>Clipboard是Android提供的一个系统服务,它提供了一个全局的剪贴板,让文字、图片、数据,在多App间共享成为可能,今天,我们来了解下它的真面目,以及被玩坏的新姿势。</p>    <p>说实话,如果不是为了让Clipboard玩出花,我真不想写这一篇,因为——这文档写的真是太TM详细了。</p>    <h2><strong>Clipboard应用</strong></h2>    <p>我们先来看看一些App对Clipboard的应用,例如手机迅雷,如果你复制了一个链接,那么打开迅雷后,会自动检测并提示下载:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0e8616960becc873ec031e6ce67f4c2a.png"></p>    <p>再例如一些翻译软件,例如有道词典、沪江小D,他们都有一个功能,即复制查词,使用的也是这个原理,我这没装这些App,就不截图了,再例如比较常用的手淘喵口令,实际上也是利用这个功能,当然,也有一些比较专业的Clipboard App,例如Clipboard Actions:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/d3a7dcec39c598d0210b1c5c197d507d.png"></p>    <p>我们可以看见,实际上,他就是帮你解析了各种可能的剪贴板,并对他们提供了各种后续功能的集合,确实非常实用,不过,看完今天的文章,相信你要写一个这样的App,估计也就分分钟。</p>    <p>OK,这些就是一些Clipboard的基本使用场景,更多场景,没有做不到,只有想不到。</p>    <h2><strong>基本使用</strong></h2>    <p>Clipboard的基本使用,就是三部曲。</p>    <p>获得ClipboardManager:</p>    <pre>  <code class="language-java">ClipboardManager mClipboardManager = mClipboardManager =   (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);</code></pre>    <p>Copy:</p>    <pre>  <code class="language-java">ClipData mClipData;  String text = "hello world";  mClipData = ClipData.newPlainText("test", text);  mClipboardManager.setPrimaryClip(mClipData);</code></pre>    <p>Paste:</p>    <pre>  <code class="language-java">ClipData clipData = mClipboardManager.getPrimaryClip();  ClipData.Item item = clipData.getItemAt(0);  String text = item.getText().toString();</code></pre>    <p>结束了,简直不能再简单,API文档也写的非常详细,Demo都写了好几个。</p>    <h2><strong>不止于文字</strong></h2>    <p>我们可以创建以下三种类型的ClipData:</p>    <table>     <thead>      <tr>       <th>类型</th>       <th>描述</th>      </tr>     </thead>     <tbody>      <tr>       <td>Text newPlainText(label, text)</td>       <td>返回ClipData对象,其中ClipData.Item对象包含一个String</td>      </tr>      <tr>       <td>URI newUri(resolver, label, URI)</td>       <td>返回ClipData对象,其中ClipData.Item对象包含一个URI</td>      </tr>      <tr>       <td>Intent newIntent(label, intent)</td>       <td>返回ClipData对象,其中ClipData.Item对象包含一个Intent</td>      </tr>     </tbody>    </table>    <p>对应的,我们也能获取到不同类型的ClipData。</p>    <h2>ClipboardManager管理</h2>    <p>ClipboardManager中有很多判断与操作方法:</p>    <table>     <thead>      <tr>       <th>类型</th>       <th>描述</th>      </tr>     </thead>     <tbody>      <tr>       <td>getPrimaryClip()</td>       <td>返回剪贴板上的当前Copy内容</td>      </tr>      <tr>       <td>getPrimaryClipDescription()</td>       <td>返回剪贴板上的当前Copy的说明</td>      </tr>      <tr>       <td>hasPrimaryClip()</td>       <td>如果当前剪贴板上存在Copy返回True</td>      </tr>      <tr>       <td>setPrimaryClip(ClipData clip)</td>       <td>设置剪贴板上的当前Copy</td>      </tr>      <tr>       <td>setText(CharSequence text)</td>       <td>设置文本到当前Copy</td>      </tr>      <tr>       <td>getText()</td>       <td>获取剪贴板复制的文本</td>      </tr>     </tbody>    </table>    <h2><strong>玩出一朵小FaFa</strong></h2>    <p>在了解了上面这些内容后,我们就可以做一些比较有意思的东西了,例如,我们可以通过监控用户剪贴板中的内容,来做一些自动的推断,例如,用户复制了一个英文单词,那么我们可以推断,用户可能要进行翻译,再例如,用户复制了一个链接,那么我们也可以推断,用户可能需要打开这个链接,等等。</p>    <p>Google在文档中,直接给出了示例的代码:</p>    <pre>  <code class="language-java">// Examines the item on the clipboard. If getText() does not return null, the clip item contains the  // text. Assumes that this application can only handle one item at a time.   ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);    // Gets the clipboard as text.  pasteData = item.getText();    // If the string contains data, then the paste operation is done  if (pasteData != null) {      return;    // The clipboard does not contain text. If it contains a URI, attempts to get data from it  } else {      Uri pasteUri = item.getUri();        // If the URI contains something, try to get text from it      if (pasteUri != null) {            // calls a routine to resolve the URI and get data from it. This routine is not          // presented here.          pasteData = resolveUri(Uri);          return;      } else {        // Something is wrong. The MIME type was plain text, but the clipboard does not contain either      // text or a Uri. Report an error.      Log.e("Clipboard contains an invalid data type");      return;      }  }</code></pre>    <p>其实非常简单,就是判断三种复制类型,但是我们可以在App中设置一些类似Scheme的标记,用来进行一些功能的区分,就好像淘宝的喵口令——『喵口令XXXXXXX喵口令』,我们可以通过解析这些Scheme,来获取内容,并进行对应的操作。这也是我们前面提到的Clipboard Actions这个App做的事情。</p>    <h2><strong>玩出一朵大FaFa</strong></h2>    <p>我们首先来看ClipData.Item.coerceToText()这样一个方法,这个方法可以将剪贴板里面的内容,直接转化为文字,但是这个转换,是有一定算法的,在API文档中有比较详细的说明,这里简单的看下:</p>    <p><img src="https://simg.open-open.com/show/9e00b40c91d8a9b852e45430dd74c784.png"></p>    <p>这个东西能干什么呢,我们知道,有些App会复制之后,打开一个Intent,为了简单,会直接通过ClipData.Item.coerceToText()来返回一个Intent的URI,然后通过解析URI来启动Intent,那么这里就可以被我们来利用了。</p>    <pre>  <code class="language-java">public void fakeClipboard() {      // 添加一个假的Intent,模拟用户最新加入的剪贴板内容      Intent intent = new Intent();      intent.setComponent(new ComponentName("com.hjwordgames", "com.hjwordgames.Splash"));      intent.setAction("android.intent.action.VIEW");      ClipData setClipData;      setClipData = ClipData.newIntent("intent", intent);      mClipboardManager.setPrimaryClip(setClipData);        // 呵呵哒 App以为获取的是自己需要的Intent,结果却被狸猫换太子      ClipData clipData = mClipboardManager.getPrimaryClip();      ClipData.Item myItem;      myItem = clipData.getItemAt(0);      String clipDataString = myItem.coerceToText(this.getApplicationContext()).toString();      try {          Intent myIntent = Intent.parseUri(clipDataString, 0);          startActivity(myIntent);      } catch (URISyntaxException e) {          e.printStackTrace();      }  }</code></pre>    <p>其实不一定是通过Fake Intent,其它的文字、图片等等,都可以被『偷天换日』。</p>    <p>另外,要实现这个监听,我们需要注册一个回调——addPrimaryClipChangedListener,Android真是体贴到没朋友:</p>    <pre>  <code class="language-java">mClipboardManager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {      @Override      public void onPrimaryClipChanged() {          Log.d("xys", "onPrimaryClipChanged: ");      }  });</code></pre>    <p>那么在这里,我们就可以完全实现剪贴板的『狸猫换太子』。那么假如我们是一个『某淘』软件的竞品,那么完全可以让『汪口令』失效,甚至替换为我们自己的应用,同理,还有一些翻译类软件也是一样,不过还好,也许是我的内心比较阴暗,目前还没有看见这样的App。</p>    <p> </p>    <p> </p>    <p>来自:http://blog.csdn.net/eclipsexys/article/details/53183802</p>    <p> </p>