-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.json
1 lines (1 loc) · 234 KB
/
search.json
1
[{"title":"okhttp+DiskLruCache实现网络缓存","url":"http://www.68blog.com/2017/04/03/14/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>因项目需要做App离线缓存,本身okhttp是带有缓存功能的,但是太鸡肋了,所以还是借助DiskLruCache完成离线缓存;</p>\n<h1 id=\"运行坏境\"><a href=\"#运行坏境\" class=\"headerlink\" title=\"运行坏境\"></a>运行坏境</h1><p>1、<a href=\"https://github.com/hongyangAndroid/okhttputils\" target=\"_blank\" rel=\"external\">okhttp</a>:大神基于okhttp封装的库;<br>2、<a href=\"https://github.com/JakeWharton/DiskLruCache\" target=\"_blank\" rel=\"external\">DiskLruCache</a>:目前的版本是2.0.2</p>\n<h1 id=\"开始编码\"><a href=\"#开始编码\" class=\"headerlink\" title=\"开始编码\"></a>开始编码</h1><p>这里我是直接把上面封装okhttp的工具库代码下载下来,再进行修改源码;<br>别忘了使用DiskLruCache要在build.gradle中引用,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">compile <span class=\"string\">'com.jakewharton:disklrucache:2.0.2'</span></div></pre></td></tr></table></figure></p>\n<p>新建缓存工具类<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div><div class=\"line\">88</div><div class=\"line\">89</div><div class=\"line\">90</div><div class=\"line\">91</div><div class=\"line\">92</div><div class=\"line\">93</div><div class=\"line\">94</div><div class=\"line\">95</div><div class=\"line\">96</div><div class=\"line\">97</div><div class=\"line\">98</div><div class=\"line\">99</div><div class=\"line\">100</div><div class=\"line\">101</div><div class=\"line\">102</div><div class=\"line\">103</div><div class=\"line\">104</div><div class=\"line\">105</div><div class=\"line\">106</div><div class=\"line\">107</div><div class=\"line\">108</div><div class=\"line\">109</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * ┏┓ ┏┓</div><div class=\"line\"> * ┏┛┻━━━┛┻┓</div><div class=\"line\"> * ┃ ┃</div><div class=\"line\"> * ┃ ━ ┃</div><div class=\"line\"> * ┃ ┳┛ ┗┳ ┃</div><div class=\"line\"> * ┃ ┃</div><div class=\"line\"> * ┃ ┻ ┃</div><div class=\"line\"> * ┃ ┃</div><div class=\"line\"> * ┗━┓ ┏━┛</div><div class=\"line\"> * ┃ ┃神兽保佑</div><div class=\"line\"> * ┃ ┃代码无BUG!</div><div class=\"line\"> * ┃ ┗━━━┓</div><div class=\"line\"> * ┃ ┣┓</div><div class=\"line\"> * ┃ ┏┛</div><div class=\"line\"> * ┗┓┓┏━┳┓┏┛</div><div class=\"line\"> * ┃┫┫ ┃┫┫</div><div class=\"line\"> * ┗┻┛ ┗┻┛</div><div class=\"line\"> * ━━━━━━神兽出没━━━━━━</div><div class=\"line\"> * Created by wdh on 2017/4/3 10:36.</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">BasicCache</span> </span>{</div><div class=\"line\"></div><div class=\"line\"> <span class=\"keyword\">private</span> DiskLruCache diskCache;</div><div class=\"line\"> <span class=\"keyword\">private</span> String fileName = <span class=\"string\">\"cache\"</span>;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"title\">BasicCache</span><span class=\"params\">(String filePath, <span class=\"keyword\">long</span> maxDiskSize)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> diskCache = DiskLruCache.open(<span class=\"keyword\">new</span> File(filePath, fileName), <span class=\"number\">1</span>, <span class=\"number\">1</span>, maxDiskSize);</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (IOException exc) {</div><div class=\"line\"> diskCache = <span class=\"keyword\">null</span>;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * url转MD5</div><div class=\"line\"> *</div><div class=\"line\"> * <span class=\"doctag\">@param</span> url</div><div class=\"line\"> * <span class=\"doctag\">@return</span></div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> String <span class=\"title\">urlToMD5</span><span class=\"params\">(HttpUrl url)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> MD5.getMD5(url.toString());</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 添加缓存数据</div><div class=\"line\"> *</div><div class=\"line\"> * <span class=\"doctag\">@param</span> response</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">addCache</span><span class=\"params\">(String date, Response response)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">if</span> (diskCache == <span class=\"keyword\">null</span>) {</div><div class=\"line\"> <span class=\"keyword\">return</span>;</div><div class=\"line\"> }</div><div class=\"line\"> Buffer buffer = <span class=\"keyword\">new</span> Buffer();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> buffer.write(date.getBytes());</div><div class=\"line\"> <span class=\"keyword\">byte</span>[] rawResponse = buffer.readByteArray();</div><div class=\"line\"> DiskLruCache.Editor editor = diskCache.edit(urlToMD5(response.request().url()));</div><div class=\"line\"> editor.set(<span class=\"number\">0</span>, <span class=\"keyword\">new</span> String(rawResponse, Charset.defaultCharset()));</div><div class=\"line\"> editor.commit();</div><div class=\"line\"> buffer.clone();</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (IOException exc) {</div><div class=\"line\"> buffer.clone();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 获取缓存数据</div><div class=\"line\"> *</div><div class=\"line\"> * <span class=\"doctag\">@param</span> request</div><div class=\"line\"> * <span class=\"doctag\">@return</span></div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> ResponseBody <span class=\"title\">getCache</span><span class=\"params\">(Request request)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">if</span> (diskCache == <span class=\"keyword\">null</span>) {</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">null</span>;</div><div class=\"line\"> }</div><div class=\"line\"> String cacheKey = urlToMD5(request.url());</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> DiskLruCache.Snapshot cacheSnapshot = diskCache.get(cacheKey);</div><div class=\"line\"> <span class=\"keyword\">if</span> (cacheSnapshot != <span class=\"keyword\">null</span>) {</div><div class=\"line\"> <span class=\"keyword\">return</span> ResponseBody.create(<span class=\"keyword\">null</span>, cacheSnapshot.getString(<span class=\"number\">0</span>).getBytes());</div><div class=\"line\"> } <span class=\"keyword\">else</span> {</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">null</span>;</div><div class=\"line\"> }</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (IOException exc) {</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">null</span>;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 删除缓存</div><div class=\"line\"> *</div><div class=\"line\"> * <span class=\"doctag\">@param</span> request</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">deleteCache</span><span class=\"params\">(Request request)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">if</span> (diskCache == <span class=\"keyword\">null</span>) {</div><div class=\"line\"> <span class=\"keyword\">return</span>;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> String cacheKey = urlToMD5(request.url());</div><div class=\"line\"> DiskLruCache.Snapshot cacheSnapshot = diskCache.get(cacheKey);</div><div class=\"line\"> <span class=\"keyword\">if</span> (cacheSnapshot != <span class=\"keyword\">null</span>) {</div><div class=\"line\"> diskCache.remove(cacheKey);</div><div class=\"line\"> }</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">CacheConfig</span> </span>{</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 缓存空间大小,默认5MB</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">long</span> disk_size = <span class=\"number\">5</span> * (<span class=\"number\">1024</span> * <span class=\"number\">1024</span>);</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 缓存目录</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"keyword\">private</span> String cache_path;</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">long</span> <span class=\"title\">getDisk_size</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> disk_size;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> CacheConfig <span class=\"title\">setDisk_size</span><span class=\"params\">(<span class=\"keyword\">long</span> disk_size)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">this</span>.disk_size = disk_size;</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">this</span>;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> String <span class=\"title\">getCache_path</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> cache_path;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> CacheConfig <span class=\"title\">setCache_path</span><span class=\"params\">(String cache_path)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">this</span>.cache_path = cache_path;</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">this</span>;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>通过调用DiskLruCache.open来返回一个DiskLruCache实例,分别需要四个参数(File directory, int appVersion, int valueCount, long maxSize),directory为缓存文件在磁盘中的路径,appVersion为app版本号,如果没有强迫症什么的填1就可以了,valueCount是单个节点对应的数据个数,通俗点说就是一个key对应多少个value,正常填1即可,maxSize是缓存的空间大小,代码简单就不一一讲解了;</p>\n<p>然后切换到请求网络的代码,在前面加上取出缓存的代码,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">if</span> (executorService == <span class=\"keyword\">null</span>) {</div><div class=\"line\"> executorService = Executors.newCachedThreadPool();</div><div class=\"line\"> }</div><div class=\"line\"> Runnable syncRunnable = <span class=\"keyword\">new</span> Runnable() {</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"comment\">//取出缓存数据</span></div><div class=\"line\"> ResponseBody responseBody = mBasicCache.getCache(requestCall.getRequest());</div><div class=\"line\"> <span class=\"keyword\">if</span> (responseBody == <span class=\"keyword\">null</span>) {</div><div class=\"line\"> <span class=\"keyword\">return</span>;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> sendSuccessResultCallback(<span class=\"keyword\">new</span> ResponseResult(<span class=\"keyword\">true</span>, responseBody.string()), finalCallback, id);</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> };</div><div class=\"line\"> executorService.execute(syncRunnable);</div></pre></td></tr></table></figure></p>\n<p>这里不建议在主线程执行但不断的new Thread()又可能造成线程没有被及时回收造成OOM等不必要的情况,所以使用ExecutorService去管理,适用于生存期短暂的异步任务,在使用缓存型池时,它会先查看池中有没有以前创建的线程,如果有,就复用,如果没有,就新建;</p>\n<p>接下来在网络请求成功的回调里面加上添加缓存的代码,如:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">mBasicCache.addCache((String) o, response);</div></pre></td></tr></table></figure></p>\n<p>OK,最后在Application中配置,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">//okhttp</span></div><div class=\"line\">OkHttpClient okHttpClient = <span class=\"keyword\">new</span> OkHttpClient.Builder()</div><div class=\"line\"> .connectTimeout(<span class=\"number\">20000</span>, TimeUnit.MILLISECONDS)</div><div class=\"line\"> .readTimeout(<span class=\"number\">20000</span>, TimeUnit.MILLISECONDS)</div><div class=\"line\"> .build();</div><div class=\"line\"><span class=\"comment\">//配置缓存</span></div><div class=\"line\">CacheConfig cacheConfig = <span class=\"keyword\">new</span> CacheConfig();</div><div class=\"line\">cacheConfig.setCache_path(APP_SDCARD_DIR).setDisk_size(<span class=\"number\">5</span> * (<span class=\"number\">1024</span> * <span class=\"number\">1024</span>));</div><div class=\"line\">OkHttpUtils.initClient(okHttpClient, cacheConfig);</div></pre></td></tr></table></figure></p>\n<h1 id=\"测试结果\"><a href=\"#测试结果\" class=\"headerlink\" title=\"测试结果\"></a>测试结果</h1><p><img src=\"http://ohci3aa1r.bkt.clouddn.com/img_network.gif\" alt=\"描述\"></p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p>如果你用的是其它的网络请求框架,原理也一样,在请求前看本地是否有缓存数据,在请求完成后每次都更新本地的缓存文件,这样也能保证本地的缓存数据是最后一次请求最新的,本文的缓存文件名用的请求URL地址转MD5作为文件的名称,本文没有对缓存数据进行加密的,如若需要可自行按照自己的加密算法进行加密;<br>android自带的LruCache是基于内存的缓存,退出应用也就没有了,DiskLruCache则是基于磁盘缓存,对于DiskLruCache就不再做多阐述,网上相关的资料很多,文章如若有误,欢迎指出;</p>\n<p>最后附上<a href=\"https://github.com/wdh-1025/android-ui\" target=\"_blank\" rel=\"external\">DEMO</a>地址,里面的okhttplib类库可以直接拿出来用,工具类包含6.0动态权限申请等;</p>\n"},{"title":"android 快速集成微信支付","url":"http://www.68blog.com/2017/02/16/13/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>众所周知,微信的开发者文档写的真的是不敢恭维,各种坑都有,有时候还遇到下载文件地址是localhost的状态,表示…,吐槽完了,对接工作还是要做的,下面开始对接微信移动支付功能;</p>\n<h1 id=\"准备工作\"><a href=\"#准备工作\" class=\"headerlink\" title=\"准备工作\"></a>准备工作</h1><p>账号申请,签约移动支付这些就不说了;<br>1、APPID<br>2、商户号<br>3、商户key(在商户平台设置的API密钥)<br>准备好这三样东西就可以动手撸码了;</p>\n<p>我们先来梳理下从生成预支付单到调起支付的整体流程:<br>1、app请求后台服务器生成预支付订单;<br>2、后台服务器调用微信统一下单接口生成预支付订单;<br>3、后台服务器拿到微信统一下单接口返回的prepayid后重新签名返回给app;<br>4、app拿到后台服务器返回的签名数据后调起微信支付;</p>\n<p>这里有个建议,在调用微信接口的时候有一些不是必填的参数能不填就不填,以免给自己带来不必要的坑;<br><a href=\"https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&lang=zh_CN\" target=\"_blank\" rel=\"external\">资源下载</a></p>\n<h1 id=\"服务端开发\"><a href=\"#服务端开发\" class=\"headerlink\" title=\"服务端开发\"></a>服务端开发</h1><p>这里我用的是PHP,java苦逼在没有tomcat服务器就用PHP简单实现;<br>先贴出PHP的全部代码再分析流程,注释清晰;<br><figure class=\"highlight php\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div><div class=\"line\">88</div><div class=\"line\">89</div><div class=\"line\">90</div><div class=\"line\">91</div><div class=\"line\">92</div><div class=\"line\">93</div><div class=\"line\">94</div><div class=\"line\">95</div><div class=\"line\">96</div><div class=\"line\">97</div><div class=\"line\">98</div><div class=\"line\">99</div><div class=\"line\">100</div><div class=\"line\">101</div><div class=\"line\">102</div><div class=\"line\">103</div><div class=\"line\">104</div><div class=\"line\">105</div><div class=\"line\">106</div><div class=\"line\">107</div><div class=\"line\">108</div><div class=\"line\">109</div><div class=\"line\">110</div><div class=\"line\">111</div><div class=\"line\">112</div><div class=\"line\">113</div><div class=\"line\">114</div><div class=\"line\">115</div><div class=\"line\">116</div><div class=\"line\">117</div><div class=\"line\">118</div><div class=\"line\">119</div><div class=\"line\">120</div><div class=\"line\">121</div><div class=\"line\">122</div><div class=\"line\">123</div><div class=\"line\">124</div><div class=\"line\">125</div><div class=\"line\">126</div><div class=\"line\">127</div><div class=\"line\">128</div><div class=\"line\">129</div><div class=\"line\">130</div><div class=\"line\">131</div><div class=\"line\">132</div><div class=\"line\">133</div><div class=\"line\">134</div><div class=\"line\">135</div><div class=\"line\">136</div><div class=\"line\">137</div><div class=\"line\">138</div><div class=\"line\">139</div><div class=\"line\">140</div><div class=\"line\">141</div><div class=\"line\">142</div><div class=\"line\">143</div><div class=\"line\">144</div><div class=\"line\">145</div><div class=\"line\">146</div><div class=\"line\">147</div><div class=\"line\">148</div><div class=\"line\">149</div><div class=\"line\">150</div><div class=\"line\">151</div><div class=\"line\">152</div><div class=\"line\">153</div><div class=\"line\">154</div><div class=\"line\">155</div><div class=\"line\">156</div><div class=\"line\">157</div><div class=\"line\">158</div><div class=\"line\">159</div><div class=\"line\">160</div><div class=\"line\">161</div><div class=\"line\">162</div><div class=\"line\">163</div><div class=\"line\">164</div><div class=\"line\">165</div><div class=\"line\">166</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"meta\"><?php</span></div><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * ┏┓ ┏┓</div><div class=\"line\"> * ┏┛┻━━━┛┻┓</div><div class=\"line\"> * ┃ ┃</div><div class=\"line\"> * ┃ ━ ┃</div><div class=\"line\"> * ┃ ┳┛ ┗┳ ┃</div><div class=\"line\"> * ┃ ┃</div><div class=\"line\"> * ┃ ┻ ┃</div><div class=\"line\"> * ┃ ┃</div><div class=\"line\"> * ┗━┓ ┏━┛</div><div class=\"line\"> * ┃ ┃神兽保佑</div><div class=\"line\"> * ┃ ┃永无BUG!</div><div class=\"line\"> * ┃ ┗━━━┓</div><div class=\"line\"> * ┃ ┣┓</div><div class=\"line\"> * ┃ ┏┛</div><div class=\"line\"> * ┗┓┓┏━┳┓┏┛</div><div class=\"line\"> * ┃┫┫ ┃┫┫</div><div class=\"line\"> * ┗┻┛ ┗┻┛</div><div class=\"line\"> * ━━━━━━神兽出没━━━━━━</div><div class=\"line\"> * Created by wdh on 2017/2/16.</div><div class=\"line\"> * Email:924686754<span class=\"doctag\">@qq</span>.com</div><div class=\"line\"> */</div><div class=\"line\">header(<span class=\"string\">\"Content-type:text/json; charset=utf-8\"</span>); </div><div class=\"line\"></div><div class=\"line\">$appid = <span class=\"string\">\"你的appId\"</span>;</div><div class=\"line\">$attach = <span class=\"string\">\"支付测试\"</span>;</div><div class=\"line\">$body = <span class=\"string\">\"APP支付测试\"</span>;</div><div class=\"line\">$mch_id = <span class=\"string\">\"你的商户号\"</span>;</div><div class=\"line\">$nonce_str = <span class=\"string\">\"\"</span>.getRandom(<span class=\"number\">32</span>);</div><div class=\"line\">$notify_url = <span class=\"string\">\"http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php\"</span>;</div><div class=\"line\">$out_trade_no = <span class=\"string\">\"\"</span>.getRandom(<span class=\"number\">32</span>);</div><div class=\"line\">$spbill_create_ip = <span class=\"string\">\"你的服务器ip\"</span>;</div><div class=\"line\">$total_fee = <span class=\"string\">\"1\"</span>;</div><div class=\"line\">$trade_type = <span class=\"string\">\"APP\"</span>; </div><div class=\"line\"></div><div class=\"line\">$timestamp = time();</div><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * 网络请求</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">do_post_request</span><span class=\"params\">($url, $data, $optional_headers = null)</span> </span>{ </div><div class=\"line\"> $params = <span class=\"keyword\">array</span>(<span class=\"string\">'http'</span> => <span class=\"keyword\">array</span>( </div><div class=\"line\"> <span class=\"string\">'method'</span> => <span class=\"string\">'POST'</span>, </div><div class=\"line\"> <span class=\"string\">'content'</span> => $data </div><div class=\"line\"> )); </div><div class=\"line\"> <span class=\"keyword\">if</span> ($optional_headers !== <span class=\"keyword\">null</span>) { </div><div class=\"line\"> $params[<span class=\"string\">'http'</span>][<span class=\"string\">'header'</span>] = $optional_headers; </div><div class=\"line\"> } </div><div class=\"line\"> $ctx = stream_context_create($params); </div><div class=\"line\"> $fp = @fopen($url, <span class=\"string\">'rb'</span>, <span class=\"keyword\">false</span>, $ctx); </div><div class=\"line\"> <span class=\"keyword\">if</span> (!$fp) { </div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> <span class=\"keyword\">Exception</span>(<span class=\"string\">\"Problem with $url, $php_errormsg\"</span>); </div><div class=\"line\"> } </div><div class=\"line\"> $response = @stream_get_contents($fp); </div><div class=\"line\"> <span class=\"keyword\">if</span> ($response === <span class=\"keyword\">false</span>) { </div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> <span class=\"keyword\">Exception</span>(<span class=\"string\">\"Problem reading data from $url, $php_errormsg\"</span>); </div><div class=\"line\"> } </div><div class=\"line\"> <span class=\"keyword\">return</span> $response; </div><div class=\"line\">} </div><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * 生成随机数</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">getRandom</span><span class=\"params\">($param)</span></span>{</div><div class=\"line\"> $str=<span class=\"string\">\"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"</span>;</div><div class=\"line\"> $key = <span class=\"string\">\"\"</span>;</div><div class=\"line\"> <span class=\"keyword\">for</span>($i=<span class=\"number\">0</span>;$i<$param;$i++)</div><div class=\"line\"> {</div><div class=\"line\"> $key .= $str{mt_rand(<span class=\"number\">0</span>,<span class=\"number\">32</span>)}; <span class=\"comment\">//生成php随机数</span></div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> $key;</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * 生成签名</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">getSign</span><span class=\"params\">()</span></span>{</div><div class=\"line\"> <span class=\"keyword\">global</span> $appid;</div><div class=\"line\"> <span class=\"keyword\">global</span> $attach;</div><div class=\"line\"> <span class=\"keyword\">global</span> $body;</div><div class=\"line\"> <span class=\"keyword\">global</span> $mch_id;</div><div class=\"line\"> <span class=\"keyword\">global</span> $nonce_str;</div><div class=\"line\"> <span class=\"keyword\">global</span> $notify_url;</div><div class=\"line\"> <span class=\"keyword\">global</span> $out_trade_no;</div><div class=\"line\"> <span class=\"keyword\">global</span> $spbill_create_ip;</div><div class=\"line\"> <span class=\"keyword\">global</span> $total_fee;</div><div class=\"line\"> <span class=\"keyword\">global</span> $trade_type; </div><div class=\"line\"> $str = <span class=\"string\">\"appid=\"</span>.$appid.<span class=\"string\">\"&attach=\"</span>.$attach.<span class=\"string\">\"&body=\"</span>.$body.<span class=\"string\">\"&mch_id=\"</span>.$mch_id.<span class=\"string\">\"&nonce_str=\"</span>.$nonce_str.<span class=\"string\">\"&notify_url=\"</span>.$notify_url.<span class=\"string\">\"&out_trade_no=\"</span>.</div><div class=\"line\"> $out_trade_no.<span class=\"string\">\"&spbill_create_ip=\"</span>.$spbill_create_ip.<span class=\"string\">\"&total_fee=\"</span>.$total_fee.<span class=\"string\">\"&trade_type=\"</span>.$trade_type.<span class=\"string\">\"&key=商户key\"</span>;</div><div class=\"line\"> $strMD5 = md5($str);</div><div class=\"line\"> <span class=\"keyword\">return</span> strtoupper($strMD5);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * 再次生成签名返回给app</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">getSign2</span><span class=\"params\">($prepayid)</span></span>{</div><div class=\"line\"> <span class=\"keyword\">global</span> $appid;</div><div class=\"line\"> <span class=\"keyword\">global</span> $timestamp;</div><div class=\"line\"> <span class=\"keyword\">global</span> $noncestr;</div><div class=\"line\"> $package = <span class=\"string\">\"Sign=WXPay\"</span>;</div><div class=\"line\"> $partnerid = <span class=\"string\">\"1278337201\"</span>;</div><div class=\"line\"> $str = <span class=\"string\">\"appid=\"</span>.$appid.<span class=\"string\">\"&noncestr=\"</span>.$noncestr.<span class=\"string\">\"&package=\"</span>.$package.<span class=\"string\">\"&partnerid=\"</span>.$partnerid.<span class=\"string\">\"&prepayid=\"</span>.$prepayid.<span class=\"string\">\"&timestamp=\"</span>.$timestamp.<span class=\"string\">\"&key=商户key\"</span>;</div><div class=\"line\"></div><div class=\"line\"> $strMD5 = md5($str);</div><div class=\"line\"> <span class=\"keyword\">return</span> strtoupper($strMD5);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">getObj</span><span class=\"params\">($status,$prepay_id,$nonce_str,$timestamp,$sign)</span></span>{</div><div class=\"line\"></div><div class=\"line\"> <span class=\"keyword\">if</span> ($status!=<span class=\"number\">200</span>) {</div><div class=\"line\"> $obj = <span class=\"string\">'{</span></div><div class=\"line\"> \"status\": 201,</div><div class=\"line\"> \"message\": \"失败\",</div><div class=\"line\"> \"params\": {</div><div class=\"line\"> }</div><div class=\"line\"> }';</div><div class=\"line\"> <span class=\"keyword\">return</span> $obj;</div><div class=\"line\"> }<span class=\"keyword\">else</span>{</div><div class=\"line\"> <span class=\"keyword\">global</span> $appid;</div><div class=\"line\"> <span class=\"keyword\">global</span> $mch_id;</div><div class=\"line\"> $obj = <span class=\"string\">'{</span></div><div class=\"line\"> \"status\": 200,</div><div class=\"line\"> \"message\": \"成功\",</div><div class=\"line\"> \"params\": {</div><div class=\"line\"> \"prepay_id\": \"'.$prepay_id.<span class=\"string\">'\",</span></div><div class=\"line\"> \"nonce_str\": \"'.$nonce_str.<span class=\"string\">'\",</span></div><div class=\"line\"> \"timestamp\": \"'.$timestamp.<span class=\"string\">'\",</span></div><div class=\"line\"> \"sign\": \"'.$sign.<span class=\"string\">'\",</span></div><div class=\"line\"> \"appId\": \"'.$appid.<span class=\"string\">'\",</span></div><div class=\"line\"> \"partnerId\":\"'.$mch_id.<span class=\"string\">'\",</span></div><div class=\"line\"> \"packageValue\":\"Sign=WXPay\"</div><div class=\"line\"> }</div><div class=\"line\"> }';</div><div class=\"line\"> <span class=\"keyword\">return</span> $obj;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\">$post_data=<span class=\"string\">\"<xml></span></div><div class=\"line\"> <appid>\".$appid.<span class=\"string\">\"</appid></span></div><div class=\"line\"> <attach>\".$attach.<span class=\"string\">\"</attach></span></div><div class=\"line\"> <body>\".$body.<span class=\"string\">\"</body></span></div><div class=\"line\"> <mch_id>\".$mch_id.<span class=\"string\">\"</mch_id></span></div><div class=\"line\"> <nonce_str>\".$nonce_str.<span class=\"string\">\"</nonce_str></span></div><div class=\"line\"> <notify_url>\".$notify_url.<span class=\"string\">\"</notify_url></span></div><div class=\"line\"> <out_trade_no>\".$out_trade_no.<span class=\"string\">\"</out_trade_no></span></div><div class=\"line\"> <spbill_create_ip>\".$spbill_create_ip.<span class=\"string\">\"</spbill_create_ip></span></div><div class=\"line\"> <total_fee>\".$total_fee.<span class=\"string\">\"</total_fee></span></div><div class=\"line\"> <trade_type>\".$trade_type.<span class=\"string\">\"</trade_type></span></div><div class=\"line\"> <sign>\".getSign().<span class=\"string\">\"</sign></span></div><div class=\"line\"></xml>\";</div><div class=\"line\"></div><div class=\"line\">$url = <span class=\"string\">\"https://api.mch.weixin.qq.com/pay/unifiedorder\"</span>;</div><div class=\"line\">$xmlstring = do_post_request($url,$post_data,<span class=\"keyword\">NULL</span>); </div><div class=\"line\"> </div><div class=\"line\">$doc=<span class=\"keyword\">new</span> DOMDocument();</div><div class=\"line\">$doc->loadXML($xmlstring); </div><div class=\"line\">$return_code = $doc->getElementsByTagname(<span class=\"string\">'return_code'</span>)->item(<span class=\"number\">0</span>)->nodeValue;</div><div class=\"line\"><span class=\"keyword\">if</span>($return_code==<span class=\"string\">\"SUCCESS\"</span>){</div><div class=\"line\"> <span class=\"comment\">//成功</span></div><div class=\"line\"> $prepay_id = $doc->getElementsByTagname(<span class=\"string\">'prepay_id'</span>)->item(<span class=\"number\">0</span>)->nodeValue;</div><div class=\"line\"> $sign = getSign2($prepay_id);</div><div class=\"line\"> <span class=\"keyword\">echo</span> getObj(<span class=\"number\">200</span>,$prepay_id,$nonce_str,$timestamp,$sign);</div><div class=\"line\">}<span class=\"keyword\">else</span>{</div><div class=\"line\"> <span class=\"comment\">//调起统一下单接口失败</span></div><div class=\"line\"> <span class=\"keyword\">echo</span> getObj(<span class=\"number\">201</span>,<span class=\"keyword\">null</span>,<span class=\"keyword\">null</span>,<span class=\"keyword\">null</span>,<span class=\"keyword\">null</span>);</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"meta\">?></span></div></pre></td></tr></table></figure></p>\n<p><font color=\"red\">注意:</font></p>\n<p><font color=\"red\">1、两次MD5的参数都必须按照字典序进行排序;</font></p>\n<p><font color=\"red\">2、生成时间戳要使用精度为秒的(10位),不能使用精度为毫秒的(13位),PHP的time()本身就是10位的,老天庇佑,让我没掉坑里;</font></p>\n<p><font color=\"red\">3、再次签名除了prepay_id用微信返回的,其他参与签名的参数全用第一次自己生成的数据;</font></p>\n<p><font color=\"red\">4、再次签名字段命名千万不能跟官方文档一样,老老实实全部写成小写</font><br><img src=\"http://ohci3aa1r.bkt.clouddn.com/KHU1Y%7D%29Z4DIT%7D5AKFOPE%7DPF.png\" alt=\"描述\"></p>\n<h1 id=\"APP开发\"><a href=\"#APP开发\" class=\"headerlink\" title=\"APP开发\"></a>APP开发</h1><p>1、引入微信的库<br>2、在包名下新建wxapi包,创建WXPayEntryActivity类,例:</p>\n<p><font color=\"red\">注意:包名和类名必须为wxapi和WXPayEntryActivity</font><br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">WXPayEntryActivity</span> <span class=\"keyword\">extends</span> <span class=\"title\">AppCompatActivity</span> <span class=\"keyword\">implements</span> <span class=\"title\">IWXAPIEventHandler</span> </span>{</div><div class=\"line\"></div><div class=\"line\"> <span class=\"keyword\">private</span> IWXAPI api;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">protected</span> <span class=\"keyword\">void</span> <span class=\"title\">onCreate</span><span class=\"params\">(@Nullable Bundle savedInstanceState)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">super</span>.onCreate(savedInstanceState);</div><div class=\"line\"> api = WXAPIFactory.createWXAPI(<span class=\"keyword\">this</span>, PayConfig.WX_APP_ID);</div><div class=\"line\"> api.handleIntent(getIntent(), <span class=\"keyword\">this</span>);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">protected</span> <span class=\"keyword\">void</span> <span class=\"title\">onNewIntent</span><span class=\"params\">(Intent intent)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">super</span>.onNewIntent(intent);</div><div class=\"line\"> setIntent(intent);</div><div class=\"line\"> api.handleIntent(intent, <span class=\"keyword\">this</span>);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">onReq</span><span class=\"params\">(BaseReq baseReq)</span> </span>{</div><div class=\"line\"></div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 回调结果的处理</div><div class=\"line\"> *</div><div class=\"line\"> * <span class=\"doctag\">@param</span> baseReq</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">onResp</span><span class=\"params\">(BaseResp baseResp)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">if</span> (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (baseResp.errCode == <span class=\"number\">0</span>) {</div><div class=\"line\"> Toast.makeText(<span class=\"keyword\">this</span>, <span class=\"string\">\"支付成功\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\"> } <span class=\"keyword\">else</span> {</div><div class=\"line\"> Toast.makeText(<span class=\"keyword\">this</span>, <span class=\"string\">\"支付失败\"</span> + baseResp.errCode + <span class=\"string\">\"str:\"</span> + baseResp.errStr, Toast.LENGTH_SHORT).show();</div><div class=\"line\"> }</div><div class=\"line\"> Log.i(<span class=\"string\">\"------\"</span>, <span class=\"string\">\"支付失败\"</span> + baseResp.errCode + <span class=\"string\">\"str:\"</span> + baseResp.transaction);</div><div class=\"line\"> finish();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>3、配置AndroidManifest文件,例:<br><figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">activity</span></span></div><div class=\"line\"> <span class=\"attr\">android:name</span>=<span class=\"string\">\".wxapi.WXPayEntryActivity\"</span></div><div class=\"line\"> <span class=\"attr\">android:exported</span>=<span class=\"string\">\"true\"</span></div><div class=\"line\"> <span class=\"attr\">android:launchMode</span>=<span class=\"string\">\"singleTop\"</span></div><div class=\"line\"> <span class=\"attr\">android:screenOrientation</span>=<span class=\"string\">\"portrait\"</span></div><div class=\"line\"> <span class=\"attr\">android:label</span>=<span class=\"string\">\"微信支付\"</span> /></div></pre></td></tr></table></figure></p>\n<p>4、在需要调用微信支付的地方调用服务器,获取返回的数据后调起微信支付,例:</p>\n<p><font color=\"red\">OrderBean是我自定义的实体类对象,也就是后台服务器返回的数据</font><br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">sendReq</span><span class=\"params\">(OrderBean mOrderBean)</span> </span>{</div><div class=\"line\"> IWXAPI api = WXAPIFactory.createWXAPI(mContext, PayConfig.WX_APP_ID);</div><div class=\"line\"> api.registerApp(PayConfig.WX_APP_ID);</div><div class=\"line\"> PayReq payRequest = <span class=\"keyword\">new</span> PayReq();</div><div class=\"line\"> payRequest.appId = mOrderBean.getAppId();</div><div class=\"line\"> payRequest.partnerId = mOrderBean.getPartnerId();</div><div class=\"line\"> payRequest.prepayId = mOrderBean.getPrepay_id();</div><div class=\"line\"> payRequest.packageValue = mOrderBean.getPackageValue();</div><div class=\"line\"> payRequest.nonceStr = mOrderBean.getNonce_str();</div><div class=\"line\"> payRequest.timeStamp = mOrderBean.getTimestamp();</div><div class=\"line\"> payRequest.sign = mOrderBean.getSign();</div><div class=\"line\"> <span class=\"keyword\">boolean</span> x = api.sendReq(payRequest);</div><div class=\"line\"> <span class=\"keyword\">if</span> (!x) {</div><div class=\"line\"> Toast.makeText(mContext, <span class=\"string\">\"请先安装微信客户端\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\"> }</div><div class=\"line\"> }</div></pre></td></tr></table></figure></p>\n<p>5、支付结果会回调到步骤2中的onResp,再做相应的业务逻辑操作(支付结果等就不上图了,还要截图还要上传到服务器,毕竟我是个比较懒的人);</p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p>集成微信支付相对简单,就是不能完全照着官方文档来,不然铁定的被坑;</p>\n"},{"title":"微信抢红包-快人一步","url":"http://www.68blog.com/2017/01/22/12/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>眼看快过年了,先祝大家新年快乐,本篇是今年最后一篇文章,想想过年到了,微信红包肯定少不了,但是每次都是比人家慢了一步,所以上网搜了一下,确实很多自动抢红包的,但是担心有一些流氓软件存在一些后门,所以还是决定自己撸一遍,其实在半年前就已经实现过类似的功能,这次权当整理了;</p>\n<h1 id=\"环境要求\"><a href=\"#环境要求\" class=\"headerlink\" title=\"环境要求\"></a>环境要求</h1><p>微信 v6.5.4</p>\n<h1 id=\"前提工作\"><a href=\"#前提工作\" class=\"headerlink\" title=\"前提工作\"></a>前提工作</h1><p>在开始编码前我们需要弄清楚微信的某个具体布局的view id是多少,这里我用的是android studio的页面分析工具,手机到了你要分析的页面后,点击AS的Tools->Android->Android Device Monitor;<br>在你连上手机后点击Dump view Hierarchy for UI Automator后会出来一个和你手机上一样的界面,点击某个view之后会有对应的text、resource-id,我们需要通过text或者resource-id去实现自动点击,下面对应的属性是checked表示这个view是否可以点击,下面类似的是android的基础知识就不一一解释了,分析好所有页面后开始编码;</p>\n<h1 id=\"开始编码\"><a href=\"#开始编码\" class=\"headerlink\" title=\"开始编码\"></a>开始编码</h1><p>首选在res文件夹下新建xml文件夹,然后新建xml文件,名字随意,只要后面写在AndroidManifest.xml中对应一样即可,例:<br><figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"php\"><span class=\"meta\"><?</span>xml version=<span class=\"string\">\"1.0\"</span> encoding=<span class=\"string\">\"utf-8\"</span><span class=\"meta\">?></span></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">accessibility-service</span> <span class=\"attr\">xmlns:android</span>=<span class=\"string\">\"http://schemas.android.com/apk/res/android\"</span></span></div><div class=\"line\"> <span class=\"attr\">android:accessibilityEventTypes</span>=<span class=\"string\">\"typeAllMask\"</span></div><div class=\"line\"> <span class=\"attr\">android:accessibilityFeedbackType</span>=<span class=\"string\">\"feedbackGeneric\"</span></div><div class=\"line\"> <span class=\"attr\">android:canRetrieveWindowContent</span>=<span class=\"string\">\"true\"</span></div><div class=\"line\"> <span class=\"attr\">android:description</span>=<span class=\"string\">\"@string/accessibility_description\"</span></div><div class=\"line\"> <span class=\"attr\">android:notificationTimeout</span>=<span class=\"string\">\"100\"</span></div><div class=\"line\"> <span class=\"attr\">android:packageNames</span>=<span class=\"string\">\"com.tencent.mm\"</span> /></div></pre></td></tr></table></figure></p>\n<p>其实看字段应该能看懂什么意思notificationTimeout是通知超时时间,packageNames是你要监听的应用包名,其它的就不一一介绍了;</p>\n<p>接下来新建一个extends AccessibilityService的service类,然后我们在onAccessibilityEvent函数中做文章:<br>我们可以通过event.getEventType();拿到事件的类型,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">int</span> eventType = event.getEventType();</div><div class=\"line\"> <span class=\"keyword\">switch</span> (eventType) {</div><div class=\"line\"> <span class=\"keyword\">case</span> AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:</div><div class=\"line\">\t\t\t\t<span class=\"comment\">// 通知栏事件</span></div><div class=\"line\"> <span class=\"keyword\">break</span>;</div><div class=\"line\"> <span class=\"keyword\">case</span> AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:</div><div class=\"line\"> \t<span class=\"comment\">//窗体状态改变</span></div><div class=\"line\"> <span class=\"keyword\">break</span>;</div><div class=\"line\"> <span class=\"keyword\">case</span> AccessibilityEvent.TYPE_VIEW_SCROLLED:</div><div class=\"line\"> \t<span class=\"comment\">//滚动</span></div><div class=\"line\"> <span class=\"keyword\">break</span>;</div><div class=\"line\"> }</div></pre></td></tr></table></figure></p>\n<p>好吧,都是很简单的功能,我觉得不必要一点点去讲解代码了,后面会给出源码下载地址,这里我讲一下实现思路:<br>1、手机解锁(如果是锁屏的情况下,必须要无密码)<br>2、点击通知栏<br>3、点击红包item<br>4、开启红包<br>5、锁屏(如果刚开始是锁屏的情况下)<br>步骤不多,可以说比较清晰简单的;<br>下面给出全部代码,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div><div class=\"line\">88</div><div class=\"line\">89</div><div class=\"line\">90</div><div class=\"line\">91</div><div class=\"line\">92</div><div class=\"line\">93</div><div class=\"line\">94</div><div class=\"line\">95</div><div class=\"line\">96</div><div class=\"line\">97</div><div class=\"line\">98</div><div class=\"line\">99</div><div class=\"line\">100</div><div class=\"line\">101</div><div class=\"line\">102</div><div class=\"line\">103</div><div class=\"line\">104</div><div class=\"line\">105</div><div class=\"line\">106</div><div class=\"line\">107</div><div class=\"line\">108</div><div class=\"line\">109</div><div class=\"line\">110</div><div class=\"line\">111</div><div class=\"line\">112</div><div class=\"line\">113</div><div class=\"line\">114</div><div class=\"line\">115</div><div class=\"line\">116</div><div class=\"line\">117</div><div class=\"line\">118</div><div class=\"line\">119</div><div class=\"line\">120</div><div class=\"line\">121</div><div class=\"line\">122</div><div class=\"line\">123</div><div class=\"line\">124</div><div class=\"line\">125</div><div class=\"line\">126</div><div class=\"line\">127</div><div class=\"line\">128</div><div class=\"line\">129</div><div class=\"line\">130</div><div class=\"line\">131</div><div class=\"line\">132</div><div class=\"line\">133</div><div class=\"line\">134</div><div class=\"line\">135</div><div class=\"line\">136</div><div class=\"line\">137</div><div class=\"line\">138</div><div class=\"line\">139</div><div class=\"line\">140</div><div class=\"line\">141</div><div class=\"line\">142</div><div class=\"line\">143</div><div class=\"line\">144</div><div class=\"line\">145</div><div class=\"line\">146</div><div class=\"line\">147</div><div class=\"line\">148</div><div class=\"line\">149</div><div class=\"line\">150</div><div class=\"line\">151</div><div class=\"line\">152</div><div class=\"line\">153</div><div class=\"line\">154</div><div class=\"line\">155</div><div class=\"line\">156</div><div class=\"line\">157</div><div class=\"line\">158</div><div class=\"line\">159</div><div class=\"line\">160</div><div class=\"line\">161</div><div class=\"line\">162</div><div class=\"line\">163</div><div class=\"line\">164</div><div class=\"line\">165</div><div class=\"line\">166</div><div class=\"line\">167</div><div class=\"line\">168</div><div class=\"line\">169</div><div class=\"line\">170</div><div class=\"line\">171</div><div class=\"line\">172</div><div class=\"line\">173</div><div class=\"line\">174</div><div class=\"line\">175</div><div class=\"line\">176</div><div class=\"line\">177</div><div class=\"line\">178</div><div class=\"line\">179</div><div class=\"line\">180</div><div class=\"line\">181</div><div class=\"line\">182</div><div class=\"line\">183</div><div class=\"line\">184</div><div class=\"line\">185</div><div class=\"line\">186</div><div class=\"line\">187</div><div class=\"line\">188</div><div class=\"line\">189</div><div class=\"line\">190</div><div class=\"line\">191</div><div class=\"line\">192</div><div class=\"line\">193</div><div class=\"line\">194</div><div class=\"line\">195</div><div class=\"line\">196</div><div class=\"line\">197</div><div class=\"line\">198</div><div class=\"line\">199</div><div class=\"line\">200</div><div class=\"line\">201</div><div class=\"line\">202</div><div class=\"line\">203</div><div class=\"line\">204</div><div class=\"line\">205</div><div class=\"line\">206</div><div class=\"line\">207</div><div class=\"line\">208</div><div class=\"line\">209</div><div class=\"line\">210</div><div class=\"line\">211</div><div class=\"line\">212</div><div class=\"line\">213</div><div class=\"line\">214</div><div class=\"line\">215</div><div class=\"line\">216</div><div class=\"line\">217</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">QinagHongBaoServier</span> <span class=\"keyword\">extends</span> <span class=\"title\">AccessibilityService</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">static</span> <span class=\"keyword\">final</span> String TAG = <span class=\"string\">\"Jackie\"</span>;</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 微信的包名</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">static</span> <span class=\"keyword\">final</span> String WECHAT_PACKAGENAME = <span class=\"string\">\"com.tencent.mm\"</span>;</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 红包消息的关键字</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">static</span> <span class=\"keyword\">final</span> String ENVELOPE_TEXT_KEY = <span class=\"string\">\"[微信红包]\"</span>;</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 在单人或者群聊页面,默认可以点击,也就是可以监听view的变化</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">boolean</span> CHAT_PAGE_CLICK = <span class=\"keyword\">true</span>;</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 判断是不是消息通知栏点击进来的</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">boolean</span> NOTIFICATION_CLICK = <span class=\"keyword\">false</span>;</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 判断是否锁屏</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">boolean</span> LOCKED = <span class=\"keyword\">false</span>;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">onAccessibilityEvent</span><span class=\"params\">(AccessibilityEvent event)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">int</span> eventType = event.getEventType();</div><div class=\"line\"> <span class=\"keyword\">switch</span> (eventType) {</div><div class=\"line\"> <span class=\"keyword\">case</span> AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:<span class=\"comment\">// 通知栏事件</span></div><div class=\"line\"> <span class=\"keyword\">if</span> (isScreenLocked()) {</div><div class=\"line\"> <span class=\"comment\">//判断是否锁屏 是的话解锁</span></div><div class=\"line\"> LOCKED = <span class=\"keyword\">true</span>;</div><div class=\"line\"> wakeAndUnlock();</div><div class=\"line\"> }</div><div class=\"line\"> List<CharSequence> texts = event.getText();</div><div class=\"line\"> <span class=\"keyword\">if</span> (!texts.isEmpty()) {</div><div class=\"line\"> <span class=\"keyword\">for</span> (CharSequence t : texts) {</div><div class=\"line\"> String text = String.valueOf(t);</div><div class=\"line\"> <span class=\"keyword\">if</span> (text.contains(ENVELOPE_TEXT_KEY)) {</div><div class=\"line\"> NOTIFICATION_CLICK = <span class=\"keyword\">true</span>;</div><div class=\"line\"> openNotification(event);</div><div class=\"line\"> <span class=\"keyword\">break</span>;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">break</span>;</div><div class=\"line\"> <span class=\"keyword\">case</span> AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:<span class=\"comment\">//窗体状态改变</span></div><div class=\"line\"> <span class=\"comment\">//窗体发生变化</span></div><div class=\"line\"> <span class=\"keyword\">if</span> (CHAT_PAGE_CLICK && NOTIFICATION_CLICK) {</div><div class=\"line\"> openEnvelope(event);</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">break</span>;</div><div class=\"line\"> <span class=\"keyword\">case</span> AccessibilityEvent.TYPE_VIEW_SCROLLED:</div><div class=\"line\"> <span class=\"keyword\">if</span> (CHAT_PAGE_CLICK && NOTIFICATION_CLICK) {</div><div class=\"line\"> openEnvelope(event);</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">break</span>;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">onInterrupt</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"></div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 打开通知栏消息</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">void</span> <span class=\"title\">openNotification</span><span class=\"params\">(AccessibilityEvent event)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">if</span> (event.getParcelableData() != <span class=\"keyword\">null</span> && event.getParcelableData() <span class=\"keyword\">instanceof</span> Notification) {</div><div class=\"line\"> Notification notification = (Notification) event.getParcelableData();</div><div class=\"line\"> PendingIntent pendingIntent = notification.contentIntent;</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> pendingIntent.send();</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (PendingIntent.CanceledException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@TargetApi</span>(Build.VERSION_CODES.JELLY_BEAN)</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">void</span> <span class=\"title\">openEnvelope</span><span class=\"params\">(AccessibilityEvent event)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"string\">\"com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyReceiveUI\"</span>.equals(event.getClassName())) {</div><div class=\"line\"> <span class=\"comment\">//点中了红包,下一步就是去拆红包222222</span></div><div class=\"line\"> checkKey1();</div><div class=\"line\"> } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"string\">\"com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI\"</span>.equals(event.getClassName())) {</div><div class=\"line\"> <span class=\"comment\">//拆完红包后看详细的纪录界面33333</span></div><div class=\"line\"> <span class=\"comment\">//拆完啦</span></div><div class=\"line\"> Toast.makeText(<span class=\"keyword\">this</span>, <span class=\"string\">\"抢完啦\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\"> <span class=\"comment\">//设置不监听单人聊天页面监听</span></div><div class=\"line\"> CHAT_PAGE_CLICK = <span class=\"keyword\">false</span>;</div><div class=\"line\"> <span class=\"comment\">//把标识设回原来的状态</span></div><div class=\"line\"> NOTIFICATION_CLICK = <span class=\"keyword\">false</span>;</div><div class=\"line\"> <span class=\"comment\">//模拟点击返回</span></div><div class=\"line\"> onBackButton();</div><div class=\"line\"> <span class=\"comment\">//抢完红包返回一秒内不点击,为了绕开返回监听到view变化又TM给点进来了</span></div><div class=\"line\"> Handler handler = <span class=\"keyword\">new</span> Handler();</div><div class=\"line\"> handler.postDelayed(runnable, <span class=\"number\">1000</span>);</div><div class=\"line\"> <span class=\"comment\">//锁屏</span></div><div class=\"line\"> releaseLocked();</div><div class=\"line\"></div><div class=\"line\"> } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"string\">\"android.widget.ListView\"</span>.equals(event.getClassName())) {</div><div class=\"line\"> <span class=\"comment\">//在聊天界面,去点中红包11111</span></div><div class=\"line\"> checkKey2();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@TargetApi</span>(Build.VERSION_CODES.JELLY_BEAN_MR2)</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">void</span> <span class=\"title\">checkKey1</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();</div><div class=\"line\"> <span class=\"keyword\">if</span> (nodeInfo == <span class=\"keyword\">null</span>) {</div><div class=\"line\"> Log.w(TAG, <span class=\"string\">\"rootWindow为空\"</span>);</div><div class=\"line\"> <span class=\"keyword\">return</span>;</div><div class=\"line\"> } <span class=\"comment\">//</span></div><div class=\"line\"> List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId(<span class=\"string\">\"com.tencent.mm:id/bi3\"</span>);</div><div class=\"line\"> <span class=\"keyword\">for</span> (AccessibilityNodeInfo n : list) {</div><div class=\"line\"> n.performAction(AccessibilityNodeInfo.ACTION_CLICK);</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@TargetApi</span>(Build.VERSION_CODES.JELLY_BEAN_MR2)</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">void</span> <span class=\"title\">checkKey2</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();</div><div class=\"line\"> <span class=\"keyword\">if</span> (nodeInfo == <span class=\"keyword\">null</span>) {</div><div class=\"line\"> Log.w(TAG, <span class=\"string\">\"rootWindow为空\"</span>);</div><div class=\"line\"> <span class=\"keyword\">return</span>;</div><div class=\"line\"> }</div><div class=\"line\"> List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText(<span class=\"string\">\"领取红包\"</span>);</div><div class=\"line\"> <span class=\"keyword\">if</span> (list.size() > <span class=\"number\">0</span>) {</div><div class=\"line\"> <span class=\"comment\">//领取最新的红包</span></div><div class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = list.size() - <span class=\"number\">1</span>; i >= <span class=\"number\">0</span>; i--) {</div><div class=\"line\"> AccessibilityNodeInfo parent = list.get(i).getParent();</div><div class=\"line\"> <span class=\"keyword\">if</span> (parent != <span class=\"keyword\">null</span>) {</div><div class=\"line\"> parent.performAction(AccessibilityNodeInfo.ACTION_CLICK);</div><div class=\"line\"> <span class=\"keyword\">break</span>;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"keyword\">private</span> Runnable runnable = <span class=\"keyword\">new</span> Runnable() {</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> CHAT_PAGE_CLICK = <span class=\"keyword\">true</span>;</div><div class=\"line\"> Log.i(<span class=\"string\">\"xxxxxxxx\"</span>, <span class=\"string\">\"我变回来啦\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> };</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 点击back返回,TMD,模拟back按键不知道为什么失败了,反正微信界面有back点击它也一样,可能就响应速度有点差别</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"meta\">@TargetApi</span>(Build.VERSION_CODES.JELLY_BEAN_MR2)</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">void</span> <span class=\"title\">onBackButton</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();</div><div class=\"line\"> <span class=\"keyword\">if</span> (nodeInfo != <span class=\"keyword\">null</span>) {</div><div class=\"line\"> List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByViewId(<span class=\"string\">\"com.tencent.mm:id/gw\"</span>);</div><div class=\"line\"> <span class=\"keyword\">if</span> (list.size() > <span class=\"number\">0</span>) {</div><div class=\"line\"> list.get(<span class=\"number\">0</span>).performAction(AccessibilityNodeInfo.ACTION_CLICK);</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 回到系统桌面</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">void</span> <span class=\"title\">back2Home</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> Intent home = <span class=\"keyword\">new</span> Intent(Intent.ACTION_MAIN);</div><div class=\"line\"> home.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);</div><div class=\"line\"> home.addCategory(Intent.CATEGORY_HOME);</div><div class=\"line\"> startActivity(home);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 系统是否在锁屏状态</div><div class=\"line\"> *</div><div class=\"line\"> * <span class=\"doctag\">@return</span></div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">boolean</span> <span class=\"title\">isScreenLocked</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);</div><div class=\"line\"> <span class=\"keyword\">return</span> keyguardManager.inKeyguardRestrictedInputMode();</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 解锁手机</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"keyword\">private</span> KeyguardManager.KeyguardLock kl;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">void</span> <span class=\"title\">wakeAndUnlock</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"comment\">//获取电源管理器对象</span></div><div class=\"line\"> PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);</div><div class=\"line\"> <span class=\"comment\">//获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是调试用的Tag</span></div><div class=\"line\"> PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, <span class=\"string\">\"bright\"</span>);</div><div class=\"line\"> <span class=\"comment\">//点亮屏幕</span></div><div class=\"line\"> wl.acquire(<span class=\"number\">1000</span>);</div><div class=\"line\"> <span class=\"comment\">//得到键盘锁管理器对象</span></div><div class=\"line\"> KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);</div><div class=\"line\"> kl = km.newKeyguardLock(<span class=\"string\">\"unLock\"</span>);</div><div class=\"line\"> <span class=\"comment\">//解锁</span></div><div class=\"line\"> kl.disableKeyguard();</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 重新锁屏</div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">private</span> <span class=\"keyword\">void</span> <span class=\"title\">releaseLocked</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">if</span> (LOCKED && kl != <span class=\"keyword\">null</span>) {</div><div class=\"line\"> android.util.Log.d(<span class=\"string\">\"maptrix\"</span>, <span class=\"string\">\"release the lock\"</span>);</div><div class=\"line\"> <span class=\"comment\">//得到键盘锁管理器对象</span></div><div class=\"line\"> kl.reenableKeyguard();</div><div class=\"line\"> LOCKED = <span class=\"keyword\">false</span>;</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>最后记得在AndroidManifest.xml中加入配置,例:<br><figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">application</span></span></div><div class=\"line\"> <span class=\"attr\">android:allowBackup</span>=<span class=\"string\">\"true\"</span></div><div class=\"line\"> <span class=\"attr\">android:icon</span>=<span class=\"string\">\"@mipmap/icon\"</span></div><div class=\"line\"> <span class=\"attr\">android:label</span>=<span class=\"string\">\"@string/app_name\"</span></div><div class=\"line\"> <span class=\"attr\">android:supportsRtl</span>=<span class=\"string\">\"true\"</span></div><div class=\"line\"> <span class=\"attr\">android:theme</span>=<span class=\"string\">\"@style/AppTheme\"</span>></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">activity</span></span></div><div class=\"line\"> <span class=\"attr\">android:name</span>=<span class=\"string\">\".MainActivity\"</span></div><div class=\"line\"> <span class=\"attr\">android:label</span>=<span class=\"string\">\"@string/app_name\"</span>></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">intent-filter</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">action</span> <span class=\"attr\">android:name</span>=<span class=\"string\">\"android.intent.action.MAIN\"</span> /></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">category</span> <span class=\"attr\">android:name</span>=<span class=\"string\">\"android.intent.category.LAUNCHER\"</span> /></span></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">intent-filter</span>></span></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">activity</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">service</span></span></div><div class=\"line\"> <span class=\"attr\">android:name</span>=<span class=\"string\">\".QinagHongBaoServier\"</span></div><div class=\"line\"> <span class=\"attr\">android:enabled</span>=<span class=\"string\">\"true\"</span></div><div class=\"line\"> <span class=\"attr\">android:exported</span>=<span class=\"string\">\"true\"</span></div><div class=\"line\"> <span class=\"attr\">android:label</span>=<span class=\"string\">\"@string/app_name\"</span></div><div class=\"line\"> <span class=\"attr\">android:permission</span>=<span class=\"string\">\"android.permission.BIND_ACCESSIBILITY_SERVICE\"</span>></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">intent-filter</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">action</span> <span class=\"attr\">android:name</span>=<span class=\"string\">\"android.accessibilityservice.AccessibilityService\"</span> /></span></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">intent-filter</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">meta-data</span></span></div><div class=\"line\"> <span class=\"attr\">android:name</span>=<span class=\"string\">\"android.accessibilityservice\"</span></div><div class=\"line\"> <span class=\"attr\">android:resource</span>=<span class=\"string\">\"@xml/envelope_service_config\"</span> /></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">service</span>></span></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">application</span>></span></div></pre></td></tr></table></figure></p>\n<h1 id=\"测试抢红包\"><a href=\"#测试抢红包\" class=\"headerlink\" title=\"测试抢红包\"></a>测试抢红包</h1><p>到设置里打开你前面对应的无障碍服务,一般是在更多设置->无障碍->你的服务名称,开启即可;<br><img src=\"http://ohci3aa1r.bkt.clouddn.com/wx-hongbao1.gif\" alt=\"描述\"></p>\n<p><a href=\"http://download.csdn.net/detail/u012938809/9743182\" target=\"_blank\" rel=\"external\">DEMO地址</a></p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p>OK,大功告成,功能还是很简单的,基于这种无障碍服务可以做很多事情(当然,包括一些流氓行为,或者可以微信自动不断搜索添加好友等,这个比较有利于微商吧),好了,文章先到这里,如果自己实现起来确实有问题的,可以下载demo查看;</p>\n"},{"title":"Android热修复-微信Tinker","url":"http://www.68blog.com/2017/01/18/11/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>正常情况下一旦线上版本出BUG时,这时候得改BUG,重新发布上线,用户重新下载安装,成本未免有点高;基于这种情况下很多热修复框架孕育而生,比较火的有:Andfix、HotFix等;本文旨在帮助没接触过Tinker的童鞋快速集成使用热修复;</p>\n<h1 id=\"本文环境\"><a href=\"#本文环境\" class=\"headerlink\" title=\"本文环境\"></a>本文环境</h1><p><a href=\"https://github.com/Tencent/tinker\" target=\"_blank\" rel=\"external\">官方地址</a><br>SdkVersion 24<br>gradle:2.2.0<br>Tinker版本 1.7.5</p>\n<h1 id=\"集成Tinker\"><a href=\"#集成Tinker\" class=\"headerlink\" title=\"集成Tinker\"></a>集成Tinker</h1><p>在项目根目录的build.gradle中添加,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">dependencies {</div><div class=\"line\"> ···</div><div class=\"line\"> classpath(<span class=\"string\">'com.tencent.tinker:tinker-patch-gradle-plugin:1.7.5'</span>)</div><div class=\"line\"> }</div></pre></td></tr></table></figure></p>\n<p>切换到module的build.gradle中添加,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">dependencies {</div><div class=\"line\">\t···</div><div class=\"line\"> provided(<span class=\"string\">'com.tencent.tinker:tinker-android-anno:1.7.5'</span>)</div><div class=\"line\"> compile(<span class=\"string\">'com.tencent.tinker:tinker-android-lib:1.7.5'</span>)</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>这里我把打包签名的jks文件配置到gradle中,例:<br>因为我这里测试用到的是项目的签名文件,所以不方便给出,需要的自行生成,毕竟这是很简单的事;<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div></pre></td><td class=\"code\"><pre><div class=\"line\">android {</div><div class=\"line\"> ···</div><div class=\"line\"> signingConfigs {</div><div class=\"line\"> release {</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"function\">storeFile <span class=\"title\">file</span><span class=\"params\">(<span class=\"string\">\"./keystore/app.jks\"</span>)</span></span></div><div class=\"line\"> storePassword \"password\"</div><div class=\"line\"> keyAlias \"alias\"</div><div class=\"line\"> keyPassword \"password\"</div><div class=\"line\"> } <span class=\"title\">catch</span> <span class=\"params\">(ex)</span> {</div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> InvalidUserDataException(ex.toString())</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> debug {</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"function\">storeFile <span class=\"title\">file</span><span class=\"params\">(<span class=\"string\">\"./keystore/app.jks\"</span>)</span></span></div><div class=\"line\"> storePassword \"password\"</div><div class=\"line\"> keyAlias \"alias\"</div><div class=\"line\"> keyPassword \"password\"</div><div class=\"line\"> } <span class=\"title\">catch</span> <span class=\"params\">(ex)</span> {</div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> InvalidUserDataException(ex.toString())</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>OK,到这里配置还是相对简单的,下面配置Tinker的gradle插件,官方demo配置还是比较麻烦的,看着就头晕,建议可以把先前的内容先复制出来,在拷贝官方demo的<a href=\"https://github.com/Tencent/tinker/blob/master/tinker-sample-android/app/build.gradle\" target=\"_blank\" rel=\"external\">build.gradle</a>进去一点点修改;</p>\n<p>如果还是懒得改,直接把下面内容复制到build.gradle最下面:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div><div class=\"line\">88</div><div class=\"line\">89</div><div class=\"line\">90</div><div class=\"line\">91</div><div class=\"line\">92</div><div class=\"line\">93</div><div class=\"line\">94</div><div class=\"line\">95</div><div class=\"line\">96</div><div class=\"line\">97</div><div class=\"line\">98</div><div class=\"line\">99</div><div class=\"line\">100</div><div class=\"line\">101</div><div class=\"line\">102</div><div class=\"line\">103</div><div class=\"line\">104</div><div class=\"line\">105</div><div class=\"line\">106</div><div class=\"line\">107</div><div class=\"line\">108</div><div class=\"line\">109</div><div class=\"line\">110</div><div class=\"line\">111</div><div class=\"line\">112</div><div class=\"line\">113</div><div class=\"line\">114</div><div class=\"line\">115</div><div class=\"line\">116</div><div class=\"line\">117</div><div class=\"line\">118</div><div class=\"line\">119</div><div class=\"line\">120</div><div class=\"line\">121</div><div class=\"line\">122</div><div class=\"line\">123</div><div class=\"line\">124</div><div class=\"line\">125</div><div class=\"line\">126</div><div class=\"line\">127</div><div class=\"line\">128</div><div class=\"line\">129</div><div class=\"line\">130</div><div class=\"line\">131</div><div class=\"line\">132</div><div class=\"line\">133</div><div class=\"line\">134</div><div class=\"line\">135</div><div class=\"line\">136</div><div class=\"line\">137</div><div class=\"line\">138</div><div class=\"line\">139</div><div class=\"line\">140</div><div class=\"line\">141</div><div class=\"line\">142</div><div class=\"line\">143</div><div class=\"line\">144</div><div class=\"line\">145</div><div class=\"line\">146</div><div class=\"line\">147</div><div class=\"line\">148</div><div class=\"line\">149</div><div class=\"line\">150</div><div class=\"line\">151</div><div class=\"line\">152</div><div class=\"line\">153</div><div class=\"line\">154</div><div class=\"line\">155</div><div class=\"line\">156</div><div class=\"line\">157</div><div class=\"line\">158</div><div class=\"line\">159</div><div class=\"line\">160</div><div class=\"line\">161</div><div class=\"line\">162</div><div class=\"line\">163</div><div class=\"line\">164</div><div class=\"line\">165</div><div class=\"line\">166</div><div class=\"line\">167</div><div class=\"line\">168</div><div class=\"line\">169</div><div class=\"line\">170</div><div class=\"line\">171</div><div class=\"line\">172</div><div class=\"line\">173</div><div class=\"line\">174</div><div class=\"line\">175</div><div class=\"line\">176</div><div class=\"line\">177</div><div class=\"line\">178</div><div class=\"line\">179</div><div class=\"line\">180</div><div class=\"line\">181</div><div class=\"line\">182</div><div class=\"line\">183</div><div class=\"line\">184</div><div class=\"line\">185</div><div class=\"line\">186</div><div class=\"line\">187</div><div class=\"line\">188</div><div class=\"line\">189</div><div class=\"line\">190</div><div class=\"line\">191</div><div class=\"line\">192</div><div class=\"line\">193</div><div class=\"line\">194</div><div class=\"line\">195</div><div class=\"line\">196</div><div class=\"line\">197</div><div class=\"line\">198</div><div class=\"line\">199</div><div class=\"line\">200</div><div class=\"line\">201</div><div class=\"line\">202</div><div class=\"line\">203</div><div class=\"line\">204</div><div class=\"line\">205</div><div class=\"line\">206</div><div class=\"line\">207</div><div class=\"line\">208</div><div class=\"line\">209</div><div class=\"line\">210</div><div class=\"line\">211</div><div class=\"line\">212</div><div class=\"line\">213</div><div class=\"line\">214</div><div class=\"line\">215</div><div class=\"line\">216</div><div class=\"line\">217</div><div class=\"line\">218</div><div class=\"line\">219</div><div class=\"line\">220</div><div class=\"line\">221</div><div class=\"line\">222</div><div class=\"line\">223</div><div class=\"line\">224</div><div class=\"line\">225</div><div class=\"line\">226</div><div class=\"line\">227</div><div class=\"line\">228</div><div class=\"line\">229</div><div class=\"line\">230</div><div class=\"line\">231</div><div class=\"line\">232</div><div class=\"line\">233</div><div class=\"line\">234</div><div class=\"line\">235</div><div class=\"line\">236</div><div class=\"line\">237</div><div class=\"line\">238</div><div class=\"line\">239</div><div class=\"line\">240</div><div class=\"line\">241</div><div class=\"line\">242</div><div class=\"line\">243</div><div class=\"line\">244</div><div class=\"line\">245</div><div class=\"line\">246</div><div class=\"line\">247</div><div class=\"line\">248</div><div class=\"line\">249</div><div class=\"line\">250</div><div class=\"line\">251</div><div class=\"line\">252</div><div class=\"line\">253</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">/**-----------------------------------配置开始-----------------------------------*/</span></div><div class=\"line\">def bakPath = file(<span class=\"string\">\"${buildDir}/bakApk/\"</span>)</div><div class=\"line\"><span class=\"function\">def <span class=\"title\">gitSha</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> String gitRev = <span class=\"string\">'11.2.3.5'</span></div><div class=\"line\"> <span class=\"keyword\">if</span> (gitRev == <span class=\"keyword\">null</span>) {</div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> GradleException(<span class=\"string\">\"can't get git rev, you should add git to system path or just input test value, such as 'testTinkerId'\"</span>)</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> gitRev</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> GradleException(<span class=\"string\">\"can't get git rev, you should add git to system path or just input test value, such as 'testTinkerId'\"</span>)</div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\">ext {</div><div class=\"line\"> tinkerEnabled = <span class=\"keyword\">true</span></div><div class=\"line\"> <span class=\"comment\">//旧apk</span></div><div class=\"line\"> tinkerOldApkPath = <span class=\"string\">\"${bakPath}/app-debug-0118-15-13-26.apk\"</span></div><div class=\"line\"> <span class=\"comment\">//旧包混淆文件</span></div><div class=\"line\"> tinkerApplyMappingPath = <span class=\"string\">\"${bakPath}/app-debug-1018-17-32-47-mapping.txt\"</span></div><div class=\"line\"> <span class=\"comment\">//旧apk R文件</span></div><div class=\"line\"> tinkerApplyResourcePath = <span class=\"string\">\"${bakPath}/app-debug-0118-15-13-26-R.txt\"</span></div><div class=\"line\"> <span class=\"comment\">//多渠道</span></div><div class=\"line\"> tinkerBuildFlavorDirectory = <span class=\"string\">\"${bakPath}/app-1018-17-32-47\"</span></div><div class=\"line\">}</div><div class=\"line\"><span class=\"function\">def <span class=\"title\">getOldApkPath</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> hasProperty(<span class=\"string\">\"OLD_APK\"</span>) ? OLD_APK : ext.tinkerOldApkPath</div><div class=\"line\">}</div><div class=\"line\"><span class=\"function\">def <span class=\"title\">getApplyMappingPath</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> hasProperty(<span class=\"string\">\"APPLY_MAPPING\"</span>) ? APPLY_MAPPING : ext.tinkerApplyMappingPath</div><div class=\"line\">}</div><div class=\"line\"><span class=\"function\">def <span class=\"title\">getApplyResourceMappingPath</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> hasProperty(<span class=\"string\">\"APPLY_RESOURCE\"</span>) ? APPLY_RESOURCE : ext.tinkerApplyResourcePath</div><div class=\"line\">}</div><div class=\"line\"><span class=\"function\">def <span class=\"title\">getTinkerIdValue</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> hasProperty(<span class=\"string\">\"TINKER_ID\"</span>) ? TINKER_ID : gitSha()</div><div class=\"line\">}</div><div class=\"line\"><span class=\"function\">def <span class=\"title\">buildWithTinker</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> hasProperty(<span class=\"string\">\"TINKER_ENABLE\"</span>) ? TINKER_ENABLE : ext.tinkerEnabled</div><div class=\"line\">}</div><div class=\"line\"><span class=\"function\">def <span class=\"title\">getTinkerBuildFlavorDirectory</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">return</span> ext.tinkerBuildFlavorDirectory</div><div class=\"line\">}</div><div class=\"line\"><span class=\"keyword\">if</span> (buildWithTinker()) {</div><div class=\"line\"> apply plugin: <span class=\"string\">'com.tencent.tinker.patch'</span></div><div class=\"line\"> tinkerPatch {</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 基准apk包路径,也就是旧包路径</div><div class=\"line\"> * */</div><div class=\"line\"> oldApk = getOldApkPath()</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 如果出现以下的情况,并且ignoreWarning为false,我们将中断编译。因为这些情况可能会导致编译出来的patch包</div><div class=\"line\"> * 带来风险:</div><div class=\"line\"> * 1. minSdkVersion小于14,但是dexMode的值为\"raw\";</div><div class=\"line\"> * 2. 新编译的安装包出现新增的四大组件(Activity, BroadcastReceiver...);</div><div class=\"line\"> * 3. 定义在dex.loader用于加载补丁的类不在main dex中;</div><div class=\"line\"> * 4. 定义在dex.loader用于加载补丁的类出现修改;</div><div class=\"line\"> * 5. resources.arsc改变,但没有使用applyResourceMapping编译。</div><div class=\"line\"> * */</div><div class=\"line\"> ignoreWarning = <span class=\"keyword\">false</span></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 在运行过程中,我们需要验证基准apk包与补丁包的签名是否一致,是否需要为你签名</div><div class=\"line\"> * */</div><div class=\"line\"> useSign = <span class=\"keyword\">true</span></div><div class=\"line\"> buildConfig {</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 可选参数;在编译新的apk时候,我们希望通过保持旧apk的proguard混淆方式,从而减少补丁包的大小。这个只</div><div class=\"line\"> * 是推荐的,但设置applyMapping会影响任何的assemble编译。</div><div class=\"line\"> * */</div><div class=\"line\"> applyMapping = getApplyMappingPath()</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 可选参数;在编译新的apk时候,我们希望通过旧apk的R.txt文件保持ResId的分配,这样不仅可以减少补丁包的</div><div class=\"line\"> * 大小,同时也避免由于ResId改变导致remote view异常。</div><div class=\"line\"> * */</div><div class=\"line\"> applyResourceMapping = getApplyResourceMappingPath()</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 在运行过程中,我们需要验证基准apk包的tinkerId是否等于补丁包的tinkerId。这个是决定补丁包能运行在哪些</div><div class=\"line\"> * 基准包上面,一般来说我们可以使用git版本号、versionName等等。</div><div class=\"line\"> * */</div><div class=\"line\"> tinkerId = getTinkerIdValue()</div><div class=\"line\"> }</div><div class=\"line\"> dex {</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 只能是'raw'或者'jar'。</div><div class=\"line\"> * 对于'raw'模式,我们将会保持输入dex的格式。</div><div class=\"line\"> * 对于'jar'模式,我们将会把输入dex重新压缩封装到jar。如果你的minSdkVersion小于14,你必须选择‘jar’模式</div><div class=\"line\"> * ,而且它更省存储空间,但是验证md5时比'raw'模式耗时()</div><div class=\"line\"> * */</div><div class=\"line\"> dexMode = <span class=\"string\">\"jar\"</span></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 是否提前生成dex,而非合成的方式。这套方案即回退成Qzone的方案,对于需要使用加固或者多flavor打包(建</div><div class=\"line\"> * 议使用其他方式生成渠道包)的用户可使用。但是这套方案需要插桩,会造成Dalvik下性能损耗以及Art补丁包可</div><div class=\"line\"> * 能过大的问题,务必谨慎使用。另外一方面,这种方案在Android N之后可能会产生问题,建议过滤N之后的用户。</div><div class=\"line\"> */</div><div class=\"line\"> usePreGeneratedPatchDex = <span class=\"keyword\">false</span></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 需要处理dex路径,支持*、?通配符,必须使用'/'分割。路径是相对安装包的,例如/assets/...</div><div class=\"line\"> */</div><div class=\"line\"> pattern = [<span class=\"string\">\"classes*.dex\"</span>,</div><div class=\"line\"> <span class=\"string\">\"assets/secondary-dex-?.jar\"</span>]</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 这一项非常重要,它定义了哪些类在加载补丁包的时候会用到。这些类是通过Tinker无法修改的类,也是一定要放在main dex的类。</div><div class=\"line\"> 这里需要定义的类有:</div><div class=\"line\"> 1. 你自己定义的Application类;</div><div class=\"line\"> 2. Tinker库中用于加载补丁包的部分类,即com.tencent.tinker.loader.*;</div><div class=\"line\"> 3. 如果你自定义了TinkerLoader,需要将它以及它引用的所有类也加入loader中;</div><div class=\"line\"> 4. 其他一些你不希望被更改的类,例如Sample中的BaseBuildInfo类。这里需要注意的是,这些类的直接引用类也</div><div class=\"line\"> 需要加入到loader中。或者你需要将这个类变成非preverify。</div><div class=\"line\"> */</div><div class=\"line\"> loader = [<span class=\"string\">\"com.tencent.tinker.loader.*\"</span>,</div><div class=\"line\"> <span class=\"comment\">//warning, you must change it with your application</span></div><div class=\"line\"> <span class=\"comment\">//TODO 换成自己的Application</span></div><div class=\"line\"> <span class=\"string\">\"com.tinker.MyApplication\"</span>,</div><div class=\"line\"> ]</div><div class=\"line\"> }</div><div class=\"line\"> lib {</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 需要处理lib路径,支持*、?通配符,必须使用'/'分割。与dex.pattern一致, 路径是相对安装包的,例如/assets/...</div><div class=\"line\"> */</div><div class=\"line\"> pattern = [<span class=\"string\">\"lib/armeabi/*.so\"</span>]</div><div class=\"line\"> }</div><div class=\"line\"> res {</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 需要处理res路径,支持*、?通配符,必须使用'/'分割。与dex.pattern一致, 路径是相对安装包的,例如/assets/...,</div><div class=\"line\"> * 务必注意的是,只有满足pattern的资源才会放到合成后的资源包。</div><div class=\"line\"> */</div><div class=\"line\"> pattern = [<span class=\"string\">\"res/*\"</span>, <span class=\"string\">\"assets/*\"</span>, <span class=\"string\">\"resources.arsc\"</span>, <span class=\"string\">\"AndroidManifest.xml\"</span>]</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 支持*、?通配符,必须使用'/'分割。若满足ignoreChange的pattern,在编译时会忽略该文件的新增、删除与修改。</div><div class=\"line\"> * 最极端的情况,ignoreChange与上面的pattern一致,即会完全忽略所有资源的修改。</div><div class=\"line\"> */</div><div class=\"line\"> ignoreChange = [<span class=\"string\">\"assets/sample_meta.txt\"</span>]</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 对于修改的资源,如果大于largeModSize,我们将使用bsdiff算法。这可以降低补丁包的大小,但是会增加合成</div><div class=\"line\"> * 时的复杂度。默认大小为100kb</div><div class=\"line\"> */</div><div class=\"line\"> largeModSize = <span class=\"number\">100</span></div><div class=\"line\"> }</div><div class=\"line\"> packageConfig {</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * configField(\"key\", \"value\"), 默认我们自动从基准安装包与新安装包的Manifest中读取tinkerId,并自动</div><div class=\"line\"> * 写入configField。在这里,你可以定义其他的信息,在运行时可以通过TinkerLoadResult.getPackageConfigByName得到相应的数值。但是建议直接通过修改代码来实现,例如BuildConfig。</div><div class=\"line\"> */</div><div class=\"line\"> configField(<span class=\"string\">\"patchMessage\"</span>, <span class=\"string\">\"tinker is sample to use\"</span>)</div><div class=\"line\"> }</div><div class=\"line\"> sevenZip {</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 例如\"com.tencent.mm:SevenZip:1.1.10\",将自动根据机器属性获得对应的7za运行文件,推荐使用</div><div class=\"line\"> */</div><div class=\"line\"> zipArtifact = <span class=\"string\">\"com.tencent.mm:SevenZip:1.1.10\"</span></div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 文件名 描述</div><div class=\"line\"> * patch_unsigned.apk 没有签名的补丁包</div><div class=\"line\"> * patch_signed.apk 签名后的补丁包</div><div class=\"line\"> * patch_signed_7zip.apk 签名后并使用7zip压缩的补丁包,也是我们通常使用的补丁包。但正式发布的时候,最好不要以.apk结尾,防止被运营商挟持。</div><div class=\"line\"> * log.txt 在编译补丁包过程的控制台日志</div><div class=\"line\"> * dex_log.txt 在编译补丁包过程关于dex的日志</div><div class=\"line\"> * so_log.txt 在编译补丁包过程关于lib的日志</div><div class=\"line\"> * tinker_result 最终在补丁包的内容,包括diff的dex、lib以及assets下面的meta文件</div><div class=\"line\"> * resources_out.zip 最终在手机上合成的全量资源apk,你可以在这里查看是否有文件遗漏</div><div class=\"line\"> * resources_out_7z.zip 根据7zip最终在手机上合成的全量资源apk</div><div class=\"line\"> * tempPatchedDexes 在Dalvik与Art平台,最终在手机上合成的完整Dex,我们可以在这里查看dex合成的产物。</div><div class=\"line\"> *</div><div class=\"line\"> *</div><div class=\"line\"> * */</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 获得所有渠道集合,并判断数量</div><div class=\"line\"> */</div><div class=\"line\"> List<String> flavors = <span class=\"keyword\">new</span> ArrayList<>();</div><div class=\"line\"> project.android.productFlavors.each { flavor -></div><div class=\"line\"> flavors.add(flavor.name)</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">boolean</span> hasFlavors = flavors.size() > <span class=\"number\">0</span></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * bak apk and mapping</div><div class=\"line\"> * 创建Task并执行文件操作</div><div class=\"line\"> */</div><div class=\"line\"> android.applicationVariants.all { variant -></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * task type, you want to bak</div><div class=\"line\"> */</div><div class=\"line\"> def taskName = variant.name</div><div class=\"line\"> def date = <span class=\"keyword\">new</span> Date().format(<span class=\"string\">\"MMdd-HH-mm-ss\"</span>)</div><div class=\"line\"></div><div class=\"line\"> tasks.all {</div><div class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"string\">\"assemble${taskName.capitalize()}\"</span>.equalsIgnoreCase(it.name)) {</div><div class=\"line\"></div><div class=\"line\"> it.doLast {</div><div class=\"line\"> copy {</div><div class=\"line\"> def fileNamePrefix = <span class=\"string\">\"${project.name}-${variant.baseName}\"</span></div><div class=\"line\"> def newFileNamePrefix = hasFlavors ? <span class=\"string\">\"${fileNamePrefix}\"</span> : <span class=\"string\">\"${fileNamePrefix}-${date}\"</span></div><div class=\"line\"> def destPath = hasFlavors ? file(<span class=\"string\">\"${bakPath}/${project.name}-${date}/${variant.flavorName}\"</span>) : bakPath</div><div class=\"line\"> from variant.outputs.outputFile</div><div class=\"line\"> into destPath</div><div class=\"line\"> rename { String fileName -></div><div class=\"line\"> fileName.replace(<span class=\"string\">\"${fileNamePrefix}.apk\"</span>, <span class=\"string\">\"${newFileNamePrefix}.apk\"</span>)</div><div class=\"line\"> }</div><div class=\"line\"> from <span class=\"string\">\"${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt\"</span></div><div class=\"line\"> into destPath</div><div class=\"line\"> rename { String fileName -></div><div class=\"line\"> fileName.replace(<span class=\"string\">\"mapping.txt\"</span>, <span class=\"string\">\"${newFileNamePrefix}-mapping.txt\"</span>)</div><div class=\"line\"> }</div><div class=\"line\"> from <span class=\"string\">\"${buildDir}/intermediates/symbols/${variant.dirName}/R.txt\"</span></div><div class=\"line\"> into destPath</div><div class=\"line\"> rename { String fileName -></div><div class=\"line\"> fileName.replace(<span class=\"string\">\"R.txt\"</span>, <span class=\"string\">\"${newFileNamePrefix}-R.txt\"</span>)</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * 如果有渠道则进行多渠道打包</div><div class=\"line\"> */</div><div class=\"line\"> project.afterEvaluate {</div><div class=\"line\"> <span class=\"comment\">//sample use for build all flavor for one time</span></div><div class=\"line\"> <span class=\"keyword\">if</span> (hasFlavors) {</div><div class=\"line\"> task(tinkerPatchAllFlavorRelease) {</div><div class=\"line\"> group = <span class=\"string\">'tinker'</span></div><div class=\"line\"> def originOldPath = getTinkerBuildFlavorDirectory()</div><div class=\"line\"> <span class=\"keyword\">for</span> (String flavor : flavors) {</div><div class=\"line\"> def tinkerTask = tasks.getByName(<span class=\"string\">\"tinkerPatch${flavor.capitalize()}Release\"</span>)</div><div class=\"line\"> dependsOn tinkerTask</div><div class=\"line\"> def preAssembleTask = tasks.getByName(<span class=\"string\">\"process${flavor.capitalize()}ReleaseManifest\"</span>)</div><div class=\"line\"> preAssembleTask.doFirst {</div><div class=\"line\"> String flavorName = preAssembleTask.name.substring(<span class=\"number\">7</span>, <span class=\"number\">8</span>).toLowerCase() + preAssembleTask.name.substring(<span class=\"number\">8</span>, preAssembleTask.name.length() - <span class=\"number\">15</span>)</div><div class=\"line\"> project.tinkerPatch.oldApk = <span class=\"string\">\"${originOldPath}/${flavorName}/${project.name}-${flavorName}-release.apk\"</span></div><div class=\"line\"> project.tinkerPatch.buildConfig.applyMapping = <span class=\"string\">\"${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-mapping.txt\"</span></div><div class=\"line\"> project.tinkerPatch.buildConfig.applyResourceMapping = <span class=\"string\">\"${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-R.txt\"</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> task(tinkerPatchAllFlavorDebug) {</div><div class=\"line\"> group = <span class=\"string\">'tinker'</span></div><div class=\"line\"> def originOldPath = getTinkerBuildFlavorDirectory()</div><div class=\"line\"> <span class=\"keyword\">for</span> (String flavor : flavors) {</div><div class=\"line\"> def tinkerTask = tasks.getByName(<span class=\"string\">\"tinkerPatch${flavor.capitalize()}Debug\"</span>)</div><div class=\"line\"> dependsOn tinkerTask</div><div class=\"line\"> def preAssembleTask = tasks.getByName(<span class=\"string\">\"process${flavor.capitalize()}DebugManifest\"</span>)</div><div class=\"line\"> preAssembleTask.doFirst {</div><div class=\"line\"> String flavorName = preAssembleTask.name.substring(<span class=\"number\">7</span>, <span class=\"number\">8</span>).toLowerCase() + preAssembleTask.name.substring(<span class=\"number\">8</span>, preAssembleTask.name.length() - <span class=\"number\">13</span>)</div><div class=\"line\"> project.tinkerPatch.oldApk = <span class=\"string\">\"${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug.apk\"</span></div><div class=\"line\"> project.tinkerPatch.buildConfig.applyMapping = <span class=\"string\">\"${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-mapping.txt\"</span></div><div class=\"line\"> project.tinkerPatch.buildConfig.applyResourceMapping = <span class=\"string\">\"${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-R.txt\"</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">/**-----------------------------------配置结束-----------------------------------*/</span></div></pre></td></tr></table></figure></p>\n<p>注意tinkerId目前暂时是写死的;<br>新建SampleApplicarion文件继承DefaultApplicationLike,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"meta\">@DefaultLifeCycle</span>(application = <span class=\"string\">\"com.tinker.MyApplication\"</span>,flags = ShareConstants.TINKER_ENABLE_ALL)</div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">SampleApplicarion</span> <span class=\"keyword\">extends</span> <span class=\"title\">DefaultApplicationLike</span> </span>{</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"title\">SampleApplicarion</span><span class=\"params\">(Application application, <span class=\"keyword\">int</span> tinkerFlags, <span class=\"keyword\">boolean</span> tinkerLoadVerifyFlag, <span class=\"keyword\">long</span> applicationStartElapsedTime, <span class=\"keyword\">long</span> applicationStartMillisTime, Intent tinkerResultIntent, Resources[] resources, ClassLoader[] classLoader, AssetManager[] assetManager)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">super</span>(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent, resources, classLoader, assetManager);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">onBaseContextAttached</span><span class=\"params\">(Context base)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">super</span>.onBaseContextAttached(base);</div><div class=\"line\"> TinkerInstaller.install(<span class=\"keyword\">this</span>);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@TargetApi</span>(Build.VERSION_CODES.ICE_CREAM_SANDWICH)</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">registerActivityLifecycleCallbacks</span><span class=\"params\">(Application.ActivityLifecycleCallbacks callback)</span> </span>{</div><div class=\"line\"> getApplication().registerActivityLifecycleCallbacks(callback);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p><font color=\"red\">上面的application=”你的包名.MyApplication”并在上一步将dex中的loader修改为:</font><br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">loader = [<span class=\"string\">\"com.tencent.tinker.loader.*\"</span>,<span class=\"string\">\"你的包名.MyApplication\"</span>,]</div></pre></td></tr></table></figure></p>\n<p>记得在AndroidManifest.xml中添加:<br><figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">uses-permission</span> <span class=\"attr\">android:name</span>=<span class=\"string\">\"android.permission.WRITE_EXTERNAL_STORAGE\"</span> /></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">uses-permission</span> <span class=\"attr\">android:name</span>=<span class=\"string\">\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"</span> /></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">application</span></span></div><div class=\"line\"> <span class=\"attr\">android:name</span>=<span class=\"string\">\".MyApplication\"</span></div><div class=\"line\"> <span class=\"attr\">android:allowBackup</span>=<span class=\"string\">\"true\"</span></div><div class=\"line\"> <span class=\"attr\">android:icon</span>=<span class=\"string\">\"@mipmap/ic_launcher\"</span></div><div class=\"line\"> <span class=\"attr\">android:label</span>=<span class=\"string\">\"@string/app_name\"</span></div><div class=\"line\"> <span class=\"attr\">android:supportsRtl</span>=<span class=\"string\">\"true\"</span></div><div class=\"line\"> <span class=\"attr\">android:theme</span>=<span class=\"string\">\"@style/AppTheme\"</span>></div><div class=\"line\"> ···</div><div class=\"line\"> ···</div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">application</span>></span></div></pre></td></tr></table></figure></p>\n<p>OK,到这里就算配置完成了,配置完了当然要测试了;</p>\n<h1 id=\"测试修复BUG\"><a href=\"#测试修复BUG\" class=\"headerlink\" title=\"测试修复BUG\"></a>测试修复BUG</h1><p>在MainActivity中添加完初始代码后点击Build->Build APK生成APK;<br><img src=\"http://ohci3aa1r.bkt.clouddn.com/tinker_1.png\" alt=\"描述\"><br>将outputs里面的apk拷贝出去安装在手机上,然后打开的build.radle修改ext,其它不管,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">ext {</div><div class=\"line\"> tinkerEnabled = <span class=\"keyword\">true</span></div><div class=\"line\"> <span class=\"comment\">//旧apk</span></div><div class=\"line\"> tinkerOldApkPath = <span class=\"string\">\"${bakPath}/app-debug-0118-16-38-14.apk\"</span></div><div class=\"line\"> ···</div><div class=\"line\"> <span class=\"comment\">//旧apk R文件</span></div><div class=\"line\"> tinkerApplyResourcePath = <span class=\"string\">\"${bakPath}/app-debug-0118-16-38-14-R.txt\"</span></div><div class=\"line\">\t···</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>然后切换到MainActivity修复你的bug,这里我添加了一张资源图片(刚好同事在玩支付宝集福,就P了张有9张”敬业福”的图片骗他们,哈哈),修复好代码后点击右侧Gradle找到:app->Tasks->tinker,然后双击tinkerPatchDebug后会在outputs下面生成tinkerPatch文件夹,其中的patch_signed_7zip.apk就是你需要的补丁:<br><img src=\"http://ohci3aa1r.bkt.clouddn.com/tinker_2.png\" alt=\"描述\"><br>将patch_signed_7zip.apk文件放到你设置的SD卡目录,调用Tinker加载补丁,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(), patchPath);</div></pre></td></tr></table></figure></p>\n<p>如果加载成功下面的tinker.isTinkerLoaded()返回的是true,例:<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Tinker tinker = Tinker.with(getApplicationContext());</div><div class=\"line\"><span class=\"keyword\">boolean</span> isLoadSuccess = tinker.isTinkerLoaded();</div><div class=\"line\"><span class=\"keyword\">if</span>(isLoadSuccess){</div><div class=\"line\">\tLog.i(TAG,<span class=\"string\">\"success\"</span>);</div><div class=\"line\">}<span class=\"keyword\">else</span>{</div><div class=\"line\">\tLog.i(TAG,<span class=\"string\">\"error\"</span>);\t</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>OK,加载补丁前点击”SHOW”会抛出空指针异常,修复完后点击”SHOW”,BUG解决:<br><img src=\"http://ohci3aa1r.bkt.clouddn.com/tinker_3.jpg\" width=\"35%\" height=\"35%\"></p>\n<p><a href=\"https://github.com/wdh-1025/WX-Tinker\" target=\"_blank\" rel=\"external\">DEMO地址</a></p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p>Tinker是腾讯出品,微信在用,我想兼容性应该不会差到哪去,相比其他热修复框架,这是个很大的优点,而且Tinker支持类替换、so库及资源的替换等,如果在相对稳定的情况下,使用Tinker用于线上产品的功能升级应该没什么问题,其它更高级的用法自行深入研究;</p>\n"},{"title":"微信小程序初探","url":"http://www.68blog.com/2017/01/01/10/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>大家元旦快乐,就在刚过去不久的2016年9月22日那天,微信内测”小程序”一经露面,便各种刷屏,一个微信小程序内测账号甚至被炒到了300多万,鉴于之前比较忙,也没内测资格,所以就静静的看着,等到最近有时间才想着回过头来看看;</p>\n<h1 id=\"开发环境\"><a href=\"#开发环境\" class=\"headerlink\" title=\"开发环境\"></a>开发环境</h1><p><a href=\"https://mp.weixin.qq.com\" target=\"_blank\" rel=\"external\">官网地址</a><br><a href=\"https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=20161230\" target=\"_blank\" rel=\"external\">IDE下载地址</a>根据自身环境下载对应的版本即可;<br>自行注册下载IDE,这里就不一一举例了,毕竟这是很简单的事;</p>\n<h1 id=\"目录结构\"><a href=\"#目录结构\" class=\"headerlink\" title=\"目录结构\"></a>目录结构</h1><h2 id=\"主体文件\"><a href=\"#主体文件\" class=\"headerlink\" title=\"主体文件\"></a>主体文件</h2><p>主体部分由三个文件组件,需要放在项目的根目录,如下:<br><code>app.js 页面逻辑</code><br><code>app.json 公共设置</code><br><code>app.wxss CSS样式</code><br>主体文件配置起到全局作用,例:app.wxss中的样式可以在其它的页面中直接引用;</p>\n<h2 id=\"页面文件\"><a href=\"#页面文件\" class=\"headerlink\" title=\"页面文件\"></a>页面文件</h2><p>页面有四个文件组件,如下:<br><code>.js 页面业务处理逻辑</code><br><code>.wxml 页面结构</code><br><code>.wxss CSS样式</code><br><code>.json 页面配置,如果app.js设置了backgroundColor选项,这里可以重新设置,如果不设置的话默认采用app.js的设置</code></p>\n<h1 id=\"开发实践\"><a href=\"#开发实践\" class=\"headerlink\" title=\"开发实践\"></a>开发实践</h1><p>基本概念弄明白了也总要整一下代码一探究竟的;<br>鉴于实现没什么难点的,就不附加代码了,直接上图:<br><a href=\"http://download.csdn.net/detail/u012938809/9726486\" target=\"_blank\" rel=\"external\">demo下载地址</a><br><img src=\"http://bmob-cdn-7815.b0.upaiyun.com/2016/12/30/f7efa17740e4e6be80adf241c9752182.gif\" alt=\"描述\"></p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p>微信小程序还是很好入门的,并且本身他自己提供很多供开发者调用的API和组件,so,开发门槛很低;<br>个人感觉微信小程序是被炒得有点过火了,首先,小程序和本地App相比,在用户体验方面基本上没有任何优势;<br>怎么说呢,算是各有好处吧,继续观望…;</p>\n"},{"title":"EventBus使用详解","url":"http://www.68blog.com/2016/12/30/9/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>当我们想通知其他组件或者某些事情发生时,我们通常使用观察者模式,所以在jdk1.5中已经帮助我们实现了观察者模式,只需要简单的继承一些类就可以快速使用,在Android中也有一个类似功能的开源库EventBus,可以很方便的帮我们实现观察者模式;</p>\n<p><a href=\"https://github.com/greenrobot/EventBus\" target=\"_blank\" rel=\"external\">EventBus github地址</a></p>\n<h1 id=\"EventBus概述\"><a href=\"#EventBus概述\" class=\"headerlink\" title=\"EventBus概述\"></a>EventBus概述</h1><p>EventBus的四个接收事件通知函数;<br><code>onEvent</code><br>如果你的事件在哪个线程发布的那么onEvent就会在哪个线程执行,也就是发布和接收是在同一线程的,使用这个方法时,在接收的函数onEvent不宜做耗时操作,不然会导致事件分发延时;<br><code>onEventMainThread</code><br>无论你的事件在哪个线程发布的,onEventMainThread都会在UI线程中执行,用于更新UI,不能做耗时操作;<br><code>onEventBackgroundThread</code><br>如果事件是在UI线程发布的,那么onEventBackgroundThread就会在子线程运行,假如事件本身就是在子线程发布的,那么onEventBackgroundThread则会直接运行在该子线程中;<br><code>onEventAsync</code><br>无论你在哪里发布事件,都会创建新的子线程去执行onEventAsync;</p>\n<h1 id=\"实践\"><a href=\"#实践\" class=\"headerlink\" title=\"实践\"></a>实践</h1><p>新建测试类<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">TestEvent</span> </span>{ </div><div class=\"line\"> <span class=\"keyword\">private</span> String mMsg; </div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"title\">TestEvent</span><span class=\"params\">(String msg)</span> </span>{ </div><div class=\"line\"> <span class=\"keyword\">this</span>.mMsg = msg; </div><div class=\"line\"> } </div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> String <span class=\"title\">getMsg</span><span class=\"params\">()</span></span>{ </div><div class=\"line\"> <span class=\"keyword\">return</span> mMsg; </div><div class=\"line\"> } </div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<h2 id=\"发布事件\"><a href=\"#发布事件\" class=\"headerlink\" title=\"发布事件\"></a>发布事件</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">EventBus.getDefault().post(<span class=\"keyword\">new</span> TestEvent(<span class=\"string\">\"The old to the driver\"</span>));</div></pre></td></tr></table></figure>\n<h2 id=\"订阅通知\"><a href=\"#订阅通知\" class=\"headerlink\" title=\"订阅通知\"></a>订阅通知</h2><p>接收函数<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">onEventMainThread</span><span class=\"params\">(TestEvent event)</span> </span>{ </div><div class=\"line\"> Log.i(<span class=\"string\">\"收到消息了:\"</span>+event.getMsg());</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p><code>注意在你订阅的地方进行订阅:EventBus.getDefault().register(this);</code><br><code>取消订阅:EventBus.getDefault().unregister(this);</code></p>\n<h2 id=\"多个接收函数\"><a href=\"#多个接收函数\" class=\"headerlink\" title=\"多个接收函数\"></a>多个接收函数</h2><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">public void onEventMainThread(TestEvent event) { </div><div class=\"line\"> Log.i("TestEvent收到消息了:"+event.getMsg());</div><div class=\"line\">} </div><div class=\"line\"> </div><div class=\"line\">public void onEventMainThread(TestEvent2 event) { </div><div class=\"line\"> Log.i("TestEvent2收到消息了:"+event.getMsg());</div><div class=\"line\">} </div><div class=\"line\"> </div><div class=\"line\">public void onEvent(TestEvent3 event) { </div><div class=\"line\"> Log.i("TestEvent3收到消息了:"+event.getMsg());</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p><code>如果你一个地方订阅了多个接收函数,那么你发布的是哪个实例,EventBus就会调用哪个接收函数;</code></p>\n<h2 id=\"多个地方订阅同一接收函数\"><a href=\"#多个地方订阅同一接收函数\" class=\"headerlink\" title=\"多个地方订阅同一接收函数\"></a>多个地方订阅同一接收函数</h2><p>Activity1<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">onEventMainThread</span><span class=\"params\">(TestEvent event)</span> </span>{ </div><div class=\"line\"> Log.i(<span class=\"string\">\"Activity1收到消息了:\"</span>+event.getMsg());</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>Activity2<br><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">onEventMainThread</span><span class=\"params\">(TestEvent event)</span> </span>{ </div><div class=\"line\"> Log.i(<span class=\"string\">\"Activity2收到消息了:\"</span>+event.getMsg());</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p><code>如果你多个地方订阅同一实例的接收函数,那么你一旦发布事件,那么这几个地方都会被执行;</code></p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p>好了,归根到底,消息的接收反正是根据你发布的消息参数而定的,EventBus是Android下高效的发布/订阅事件总线机制,可以代替传统的Intent,Handler,Broadcast或接口函数在Fragment,Activity,Service,线程之间传递数据,执行方法,特点是代码简洁,是一种发布订阅设计模式(Publish/Subsribe),或称作观察者设计模式;</p>\n"},{"title":"Android 动画之加速器","url":"http://www.68blog.com/2016/12/13/8/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>一个应用最吸引人的无非是良好的用户体验,好的用户体验当然也少不了动画效果,android本身就自带有很多丰富的动画效果供我们使用,本文以”加速器”为例;</p>\n<h1 id=\"加速器\"><a href=\"#加速器\" class=\"headerlink\" title=\"加速器\"></a>加速器</h1><h2 id=\"越来越快\"><a href=\"#越来越快\" class=\"headerlink\" title=\"越来越快\"></a>越来越快</h2><p>@android:anim/accelerate_interpolator</p>\n<h2 id=\"越来越慢\"><a href=\"#越来越慢\" class=\"headerlink\" title=\"越来越慢\"></a>越来越慢</h2><p>@android:anim/decelerate_interpolator</p>\n<h2 id=\"先快后慢\"><a href=\"#先快后慢\" class=\"headerlink\" title=\"先快后慢\"></a>先快后慢</h2><p>@android:anim/accelerate_decelerate_interpolator</p>\n<h2 id=\"先后退一小步然后向前加速\"><a href=\"#先后退一小步然后向前加速\" class=\"headerlink\" title=\"先后退一小步然后向前加速\"></a>先后退一小步然后向前加速</h2><p>@android:anim/anticipate_interpolator</p>\n<h2 id=\"快速到达终点超出一小步然后回到终点\"><a href=\"#快速到达终点超出一小步然后回到终点\" class=\"headerlink\" title=\"快速到达终点超出一小步然后回到终点\"></a>快速到达终点超出一小步然后回到终点</h2><p>@android:anim/overshoot_interpolator</p>\n<h2 id=\"到达终点超出一小步然后回到终点\"><a href=\"#到达终点超出一小步然后回到终点\" class=\"headerlink\" title=\"到达终点超出一小步然后回到终点\"></a>到达终点超出一小步然后回到终点</h2><p>@android:anim/anticipate_overshoot_interpolator</p>\n<h2 id=\"到达终点产生弹球效果,弹几下回到终点\"><a href=\"#到达终点产生弹球效果,弹几下回到终点\" class=\"headerlink\" title=\"到达终点产生弹球效果,弹几下回到终点\"></a>到达终点产生弹球效果,弹几下回到终点</h2><p>@android:anim/bounce_interpolator</p>\n<h2 id=\"均匀速度\"><a href=\"#均匀速度\" class=\"headerlink\" title=\"均匀速度\"></a>均匀速度</h2><p>@android:anim/linear_interpolator</p>\n<h1 id=\"使用方法\"><a href=\"#使用方法\" class=\"headerlink\" title=\"使用方法\"></a>使用方法</h1><figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"php\"><span class=\"meta\"><?</span>xml version=<span class=\"string\">\"1.0\"</span> encoding=<span class=\"string\">\"utf-8\"</span><span class=\"meta\">?></span></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">translate</span> <span class=\"attr\">xmlns:android</span>=<span class=\"string\">\"http://schemas.android.com/apk/res/android\"</span> </span></div><div class=\"line\"> <span class=\"attr\">android:duration</span>=<span class=\"string\">\"1000\"</span> </div><div class=\"line\"> <span class=\"attr\">android:fromYDelta</span>=<span class=\"string\">\"-100%\"</span> </div><div class=\"line\"> <span class=\"attr\">android:interpolator</span>=<span class=\"string\">\"@android:anim/accelerate_interpolator\"</span> /></div></pre></td></tr></table></figure>\n"},{"title":"Android 快速快发","url":"http://www.68blog.com/2016/12/12/7/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>项目旨在帮助开发者快速开发android,项目集成6.0权限申请,常用dialog,本地图片选择,侧滑回退等;<br>项目正在不断有空更新, 别急,先star吧…</p>\n<p><a href=\"https://github.com/wdh-1025/android-ui\" target=\"_blank\" rel=\"external\">github地址</a></p>\n<p><code>项目部分引用第三方开源库,感谢开源</code></p>\n<h1 id=\"权限申请\"><a href=\"#权限申请\" class=\"headerlink\" title=\"权限申请\"></a>权限申请</h1><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div></pre></td><td class=\"code\"><pre><div class=\"line\">Permission.getInstance(this)</div><div class=\"line\"> .requestPermission(Manifest.permission.CAMERA)</div><div class=\"line\"> .results(new ResultCallBack() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void result(PermissionsResult result) {</div><div class=\"line\"> if (result.isGranted()) {</div><div class=\"line\"> //有权限</div><div class=\"line\"> Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);</div><div class=\"line\"> startActivityForResult(intent, 1);</div><div class=\"line\"> Toast.makeText(MainActivity.this, "有权限啦", Toast.LENGTH_SHORT).show();</div><div class=\"line\"> } else {</div><div class=\"line\"> //被拒绝</div><div class=\"line\"> Toast.makeText(MainActivity.this, "用户拒绝了你的申请", Toast.LENGTH_SHORT).show();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> });</div></pre></td></tr></table></figure>\n<p>可以看出权限申请变得很简洁,也不用重写onRequestPermissionsResult了,因为在内部已经重写了,so,直接用,如果是申请多个权限的话,这里的回调会回调多次,自己可以根据getPermission()判断指定权限再做相应的业务逻辑处理;</p>\n<h1 id=\"图片选择-单选-多选\"><a href=\"#图片选择-单选-多选\" class=\"headerlink\" title=\"图片选择(单选/多选)\"></a>图片选择(单选/多选)</h1><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div></pre></td><td class=\"code\"><pre><div class=\"line\">PhotoPickerIntent intent = new PhotoPickerIntent(this);</div><div class=\"line\">intent.setShowCamera(true);</div><div class=\"line\">intent.setTailoring(true);</div><div class=\"line\"> intent.setPhotoCount(1);</div><div class=\"line\"> intent.setImageSelect(new PhotoPickerActivity.CallbackHead() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void selectResults(Bitmap bitmap, List<String> selectedPhotos) {</div><div class=\"line\"> //注意:如果选择的是多张图片的话bitmap为null,只返回selectedPhotos</div><div class=\"line\"> if (bitmap != null) {</div><div class=\"line\"> imageChoose.setImageBitmap(bitmap);</div><div class=\"line\"> } else {</div><div class=\"line\"> Log.i("TAG","选择了" + selectedPhotos.size() + "张照片");</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"> });</div><div class=\"line\"> startActivity(intent);</div></pre></td></tr></table></figure>\n<h1 id=\"下拉刷新上拉加载更多\"><a href=\"#下拉刷新上拉加载更多\" class=\"headerlink\" title=\"下拉刷新上拉加载更多\"></a>下拉刷新上拉加载更多</h1><p>Activity<br><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div></pre></td><td class=\"code\"><pre><div class=\"line\">public class ListActivity extends BaseListActivity<String> {</div><div class=\"line\"> @Override</div><div class=\"line\"> protected void OnViewCreated() {</div><div class=\"line\"> showLoading();</div><div class=\"line\"> Handler handler = new Handler();</div><div class=\"line\"> handler.postDelayed(new Runnable() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void run() {</div><div class=\"line\"> hideEmptyLayout();</div><div class=\"line\"> }</div><div class=\"line\"> }, 1000);</div><div class=\"line\"> }</div><div class=\"line\"> @Override</div><div class=\"line\"> public void requestData(boolean needRefresh) {</div><div class=\"line\"> Handler handler = new Handler();</div><div class=\"line\"> handler.postDelayed(new Runnable() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void run() {</div><div class=\"line\"> List<String> mData = new ArrayList<>();</div><div class=\"line\"> for (int i = 0; i < 15; i++) {</div><div class=\"line\"> mData.add("我沙发哈撒" + i + "自行车自行车");</div><div class=\"line\"> }</div><div class=\"line\"> onDataLoaded(mData);</div><div class=\"line\"> }</div><div class=\"line\"> }, 1000);</div><div class=\"line\"> }</div><div class=\"line\"> @Override</div><div class=\"line\"> protected BaseListAdapter<String> getListAdapter() {</div><div class=\"line\"> return new ATListAdapter(this);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>Adapter<br><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div></pre></td><td class=\"code\"><pre><div class=\"line\">public class ATListAdapter extends BaseListAdapter<String> {</div><div class=\"line\"></div><div class=\"line\"> public ATListAdapter(Context context) {</div><div class=\"line\"> super(context, R.layout.item_list);</div><div class=\"line\"> }</div><div class=\"line\"> @Override</div><div class=\"line\"> protected void onBindContentViewData(BaseViewHolder helper, String item, int position) {</div><div class=\"line\"> helper.setText(R.id.tv, item);</div><div class=\"line\"> }</div><div class=\"line\"> @Override</div><div class=\"line\"> protected void onBindHeadViewData(BaseViewHolder helper, int position) {</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>如果需要添加头部则super(context, R.layout.item_list,R.layout.head_layout);</p>\n<p>可以很简单的实现下拉刷新、上拉加载更多,如果需要自定义布局文件则需要重写getBaseSettings();<br>示例<br><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">@Override</div><div class=\"line\">protected ListSettings getBaseSettings() {</div><div class=\"line\"> ListSettings settings = new ListSettings();</div><div class=\"line\"> settings.setLayoutType(ListSettings.LAYOUT_LIST);</div><div class=\"line\"> settings.setCustomLayoutId(YOUR Layout);</div><div class=\"line\"> settings.setContentDividerColor(Color.parseColor("#b3b3b3"));</div><div class=\"line\"> settings.setContentDividerHeight(1);</div><div class=\"line\"> return settings;</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>设置选项可以查看ListSettings类,里面有注释;<br><a href=\"http://bmob-cdn-7815.b0.upaiyun.com/2016/11/28/3655363f40426023800e8e12070e56d7.apk\" target=\"_blank\" rel=\"external\">其它请自行下载demo查看</a></p>\n"},{"title":"java炸金花辅助类","url":"http://www.68blog.com/2016/12/04/6/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>本文主要实现炸金花辅助类,实现方式很简单,炸金花的玩法是3张为一副牌,一副扑克有54张牌,除去两张老鬼,可以算出所有组合牌型为”52 <em> 51 </em> 50/(3*2)=22100”种结果;<br>好吧,我们来一步步实现绝对定位查询大小;</p>\n<h1 id=\"22100种结果\"><a href=\"#22100种结果\" class=\"headerlink\" title=\"22100种结果\"></a>22100种结果</h1><ul>\n<li>这里我们先算出所有牌型的结果,并按从大到小的顺序并且不同牌型进行归类排序;<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">private</span> Map<String, Integer> <span class=\"title\">getResultsPats</span><span class=\"params\">()</span> </span>{</div><div class=\"line\">\t<span class=\"keyword\">if</span> (resultsPosition.size() > <span class=\"number\">0</span>) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> resultsPosition;</div><div class=\"line\">\t} <span class=\"keyword\">else</span> {</div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i <= <span class=\"number\">49</span>; i++) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> j = i + <span class=\"number\">1</span>; j <= <span class=\"number\">50</span>; j++) {</div><div class=\"line\">\t\t\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> k = j + <span class=\"number\">1</span>; k <= <span class=\"number\">51</span>; k++) {</div><div class=\"line\">\t\t\t\t\tString pata = pats.get(i);</div><div class=\"line\">\t\t\t\t\tString patb = pats.get(j);</div><div class=\"line\">\t\t\t\t\tString patc = pats.get(k);</div><div class=\"line\">\t\t\t\t\t<span class=\"keyword\">if</span> (ISBZ(pata, patb, patc)) {</div><div class=\"line\">\t\t\t\t\t\tBZ.add(pata + <span class=\"string\">\"-\"</span> + patb + <span class=\"string\">\"-\"</span> + patc);</div><div class=\"line\">\t\t\t\t\t} <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (ISTHS(pata, patb, patc)) {</div><div class=\"line\">\t\t\t\t\t\tTHS.add(pata + <span class=\"string\">\"-\"</span> + patb + <span class=\"string\">\"-\"</span> + patc);</div><div class=\"line\">\t\t\t\t\t} <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (ISTH(pata, patb, patc)) {</div><div class=\"line\">\t\t\t\t\t\tTH.add(pata + <span class=\"string\">\"-\"</span> + patb + <span class=\"string\">\"-\"</span> + patc);</div><div class=\"line\">\t\t\t\t\t} <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (ISSZ(pata, patb, patc)) {</div><div class=\"line\">\t\t\t\t\t\tSZ.add(pata + <span class=\"string\">\"-\"</span> + patb + <span class=\"string\">\"-\"</span> + patc);</div><div class=\"line\">\t\t\t\t\t} <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (ISDZ(pata, patb, patc)) {</div><div class=\"line\">\t\t\t\t\t\tDZ.add(pata + <span class=\"string\">\"-\"</span> + patb + <span class=\"string\">\"-\"</span> + patc);</div><div class=\"line\">\t\t\t\t\t} <span class=\"keyword\">else</span> {</div><div class=\"line\">\t\t\t\t\t\tSP.add(pata + <span class=\"string\">\"-\"</span> + patb + <span class=\"string\">\"-\"</span> + patc);</div><div class=\"line\">\t\t\t\t\t}</div><div class=\"line\">\t\t\t\t}</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"comment\">// 按照游戏规则</span></div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < BZ.size(); i++) {</div><div class=\"line\">\t\t\tresultsPosition.put(BZ.get(i), typeSize);</div><div class=\"line\">\t\t\ttypeSize++;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < THS.size(); i++) {</div><div class=\"line\">\t\t\tresultsPosition.put(THS.get(i), typeSize);</div><div class=\"line\">\t\t\ttypeSize++;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < TH.size(); i++) {</div><div class=\"line\">\t\t\tresultsPosition.put(TH.get(i), typeSize);</div><div class=\"line\">\t\t\ttypeSize++;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < SZ.size(); i++) {</div><div class=\"line\">\t\t\tresultsPosition.put(SZ.get(i), typeSize);</div><div class=\"line\">\t\t\ttypeSize++;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < DZ.size(); i++) {</div><div class=\"line\">\t\t\tresultsPosition.put(DZ.get(i), typeSize);</div><div class=\"line\">\t\t\ttypeSize++;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < SP.size(); i++) {</div><div class=\"line\">\t\t\tresultsPosition.put(SP.get(i), typeSize);</div><div class=\"line\">\t\t\ttypeSize++;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> resultsPosition;</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<h1 id=\"牌型判断\"><a href=\"#牌型判断\" class=\"headerlink\" title=\"牌型判断\"></a>牌型判断</h1><ul>\n<li><p>是不是豹子</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">boolean</span> <span class=\"title\">ISBZ</span><span class=\"params\">(String... pats)</span> </span>{</div><div class=\"line\">\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t<span class=\"keyword\">if</span> (pats.length != <span class=\"number\">3</span>) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\tString a = pats[<span class=\"number\">0</span>].substring(<span class=\"number\">2</span>, pats[<span class=\"number\">0</span>].length());</div><div class=\"line\">\t\tString b = pats[<span class=\"number\">1</span>].substring(<span class=\"number\">2</span>, pats[<span class=\"number\">1</span>].length());</div><div class=\"line\">\t\tString c = pats[<span class=\"number\">2</span>].substring(<span class=\"number\">2</span>, pats[<span class=\"number\">2</span>].length());</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> StringsUtils.INSTANCE.checkValueSame(a, b, c);</div><div class=\"line\">\t} <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n<li><p>是不是同花顺</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">boolean</span> <span class=\"title\">ISTHS</span><span class=\"params\">(String... pats)</span> </span>{</div><div class=\"line\">\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t<span class=\"keyword\">if</span> (pats.length != <span class=\"number\">3</span>) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"comment\">// 先判断是不是顺子,再判断花色</span></div><div class=\"line\">\t\tString[] HS = getHS(pats);</div><div class=\"line\">\t\tInteger[] newPats = PatToInt(pats);</div><div class=\"line\">\t\t<span class=\"comment\">// 先找到数组中的最小值</span></div><div class=\"line\">\t\t<span class=\"keyword\">int</span> min = newPats[<span class=\"number\">0</span>];</div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < newPats.length; i++) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">if</span> (newPats[i] < min) {</div><div class=\"line\">\t\t\t\tmin = newPats[i];</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">if</span> (!StringsUtils.INSTANCE.checkValueExist(newPats, min + <span class=\"number\">1</span>)) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t\t} <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (!StringsUtils.INSTANCE.checkValueExist(newPats, min + <span class=\"number\">2</span>)) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t\t} <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (!StringsUtils.INSTANCE.checkValueSame(HS)) {<span class=\"comment\">// 是顺子,判断是不是同花</span></div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">true</span>;</div><div class=\"line\">\t} <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n<li><p>是不是同花</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">boolean</span> <span class=\"title\">ISTH</span><span class=\"params\">(String... pats)</span> </span>{</div><div class=\"line\">\t<span class=\"keyword\">if</span> (pats.length != <span class=\"number\">3</span>) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t}</div><div class=\"line\">\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\tString[] HS = getHS(pats);</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> StringsUtils.INSTANCE.checkValueSame(HS);</div><div class=\"line\">\t} <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n<li><p>是不是顺子</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">boolean</span> <span class=\"title\">ISSZ</span><span class=\"params\">(String... pats)</span> </span>{</div><div class=\"line\">\t<span class=\"keyword\">if</span> (pats.length != <span class=\"number\">3</span>) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t}</div><div class=\"line\">\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\tInteger[] newPats = PatToInt(pats);</div><div class=\"line\">\t\t<span class=\"comment\">// 先找到数组中的最小值</span></div><div class=\"line\">\t\t<span class=\"keyword\">int</span> min = newPats[<span class=\"number\">0</span>];</div><div class=\"line\">\t\t<span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < newPats.length; i++) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">if</span> (newPats[i] < min) {</div><div class=\"line\">\t\t\t\tmin = newPats[i];</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">if</span> (!StringsUtils.INSTANCE.checkValueExist(newPats, min + <span class=\"number\">1</span>)) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t\t} <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (!StringsUtils.INSTANCE.checkValueExist(newPats, min + <span class=\"number\">2</span>)) {</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t\t} <span class=\"keyword\">else</span> {</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">true</span>;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t} <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t}</div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n<li><p>是不是对子</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">boolean</span> <span class=\"title\">ISDZ</span><span class=\"params\">(String... pats)</span> </span>{</div><div class=\"line\">\t<span class=\"keyword\">if</span> (pats.length != <span class=\"number\">3</span>) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t}</div><div class=\"line\">\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\tInteger[] newPats = PatToInt(pats);</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> StringsUtils.INSTANCE.checkRepeat(newPats);</div><div class=\"line\">\t} <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">\t}</div><div class=\"line\"></div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<h1 id=\"牌型判断绝对大小\"><a href=\"#牌型判断绝对大小\" class=\"headerlink\" title=\"牌型判断绝对大小\"></a>牌型判断绝对大小</h1><ul>\n<li><p>判断牌型绝对大小,0为最大;</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">int</span> <span class=\"title\">getPatTypePosition</span><span class=\"params\">(String... pats)</span> </span>{</div><div class=\"line\">\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t<span class=\"keyword\">if</span> (resultsPosition.size() == <span class=\"number\">0</span>) {</div><div class=\"line\">\t\t\tgetResultsPats();</div><div class=\"line\">\t\t}</div><div class=\"line\">\t\t<span class=\"keyword\">if</span> (pats != <span class=\"keyword\">null</span> && pats.length == <span class=\"number\">3</span>) {</div><div class=\"line\">\t\t\tString patStr = PatSort(pats);</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> resultsPosition.get(patStr);</div><div class=\"line\">\t\t} <span class=\"keyword\">else</span> {</div><div class=\"line\">\t\t\t<span class=\"keyword\">return</span> -<span class=\"number\">1</span>;</div><div class=\"line\">\t\t}</div><div class=\"line\">\t} <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> -<span class=\"number\">1</span>;</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n<li><p>获取52张牌随意一张的绝对大小位置</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">int</span> <span class=\"title\">getPatPositon</span><span class=\"params\">(String pat)</span> </span>{</div><div class=\"line\">\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> patPosition.get(pat);</div><div class=\"line\">\t} <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\">\t\t<span class=\"keyword\">return</span> -<span class=\"number\">1</span>;</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<h1 id=\"源码传送门\"><a href=\"#源码传送门\" class=\"headerlink\" title=\"源码传送门\"></a>源码传送门</h1><p>源码在<a href=\"https://github.com/wdh-1025/java-zjh-utils\" target=\"_blank\" rel=\"external\">这里</a></p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p>总体实现非常简单,”梭哈”游戏类似”52 <em> 51 </em> 50 <em> 49 </em>48/(5<em>4</em>3*2)=2598960”,你可自行下载源码进行修改;PS:文中代码不全,自行查看源码文件;</p>\n"},{"title":"Android Realm","url":"http://www.68blog.com/2016/11/08/5/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p>Realm用于数据库数据存储,在android端可用来替代sqlite,它有自己的数据存储引擎,更轻量级,支持JSON,流式API,数据变更通知,最主要的是它<font color=\"blue\">跨平台</font>,本文仅实现在android上的增删查改,其它请参照<a href=\"https://realm.io/docs/java/latest/\" target=\"_blank\" rel=\"external\">官方文档</a>自行实现。</p>\n<h1 id=\"运行配置\"><a href=\"#运行配置\" class=\"headerlink\" title=\"运行配置\"></a>运行配置</h1><ul>\n<li><p>在项目根目录的build.gradle加上如下代码:</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">classpath <span class=\"string\">\"io.realm:realm-gradle-plugin:2.0.2\"</span></div></pre></td></tr></table></figure>\n</li>\n<li><p>在app的build.gradle加上如下代码:</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">apply plugin: <span class=\"string\">'realm-android'</span></div></pre></td></tr></table></figure>\n</li>\n</ul>\n<h1 id=\"初始化Realm\"><a href=\"#初始化Realm\" class=\"headerlink\" title=\"初始化Realm\"></a>初始化Realm</h1><p>建议在你的Application中进行初始化,如下代码:<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">Realm.init(this);</div><div class=\"line\"> //使用自定义配置</div><div class=\"line\"> //64位的KEY,用于加解密数据</div><div class=\"line\"> String key = <span class=\"string\">\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"</span>;</div><div class=\"line\"> RealmConfiguration config = new RealmConfiguration.Builder()</div><div class=\"line\"> \t.name(<span class=\"string\">\"MyRealmDB.realm\"</span>)</div><div class=\"line\"> .encryptionKey(key.getBytes())</div><div class=\"line\"> .deleteRealmIfMigrationNeeded()</div><div class=\"line\"> .build();</div><div class=\"line\"> Realm.setDefaultConfiguration(config);</div></pre></td></tr></table></figure></p>\n<ul>\n<li>创建实体类,以“书本”为例,如下代码:<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div></pre></td><td class=\"code\"><pre><div class=\"line\">public class Book extends RealmObject {</div><div class=\"line\"> private String bookName;</div><div class=\"line\"> private int bookPrice;</div><div class=\"line\"> private RealmList<BookDirectory> directorys;</div><div class=\"line\"> public <span class=\"function\"><span class=\"title\">Book</span></span>() {</div><div class=\"line\"> }</div><div class=\"line\"> public String <span class=\"function\"><span class=\"title\">getBookName</span></span>() {</div><div class=\"line\"> <span class=\"built_in\">return</span> bookName;</div><div class=\"line\"> }</div><div class=\"line\"> public void <span class=\"built_in\">set</span>BookName(String bookName) {</div><div class=\"line\"> this.bookName = bookName;</div><div class=\"line\"> }</div><div class=\"line\"> public int <span class=\"function\"><span class=\"title\">getBookPrice</span></span>() {</div><div class=\"line\"> <span class=\"built_in\">return</span> bookPrice;</div><div class=\"line\"> }</div><div class=\"line\"> public void <span class=\"built_in\">set</span>BookPrice(int bookPrice) {</div><div class=\"line\"> this.bookPrice = bookPrice;</div><div class=\"line\"> }</div><div class=\"line\"> public RealmList<BookDirectory> <span class=\"function\"><span class=\"title\">getDirectorys</span></span>() {</div><div class=\"line\"> <span class=\"built_in\">return</span> directorys;</div><div class=\"line\"> }</div><div class=\"line\"> public void <span class=\"built_in\">set</span>Directorys(RealmList<BookDirectory> directorys) {</div><div class=\"line\"> this.directorys = directorys;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div></pre></td><td class=\"code\"><pre><div class=\"line\">public class BookDirectory extends RealmObject {</div><div class=\"line\"> private String name;</div><div class=\"line\"> private String describe;</div><div class=\"line\"> public <span class=\"function\"><span class=\"title\">BookDirectory</span></span>() {</div><div class=\"line\"> }</div><div class=\"line\"> public String <span class=\"function\"><span class=\"title\">getName</span></span>() {</div><div class=\"line\"> <span class=\"built_in\">return</span> name;</div><div class=\"line\"> }</div><div class=\"line\"> public void <span class=\"built_in\">set</span>Name(String name) {</div><div class=\"line\"> this.name = name;</div><div class=\"line\"> }</div><div class=\"line\"> public String <span class=\"function\"><span class=\"title\">getDescribe</span></span>() {</div><div class=\"line\"> <span class=\"built_in\">return</span> describe;</div><div class=\"line\"> }</div><div class=\"line\"> public void <span class=\"built_in\">set</span>Describe(String describe) {</div><div class=\"line\"> this.describe = describe;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h1 id=\"注解说明\"><a href=\"#注解说明\" class=\"headerlink\" title=\"注解说明\"></a>注解说明</h1><ul>\n<li>支持的数据类型:<br>boolean, byte, short, int, long, float, double, String, Date and byte[]<br><font color=\"red\">在Realm中byte, short, int, long最终都被映射成long类型</font><br>@PrimaryKey<br>字段必须是String、 integer、byte、short、 int、long<br>使用该注解之后可以使用copyToRealmOrUpdate()方法,通过主键查询它的对象,如果查询到了,则更新它,否则新建一个对象来代替。<br>该注解将默认设置@Index注解<br>@Required<br>表示该字段数据不能为null<br>@Ignore<br>忽略,即该字段不被存储到本地<br>@Index<br>为这个字段添加一个搜索引擎,随着数据越多插入数据就越慢,但是查询会很快,类似数据库的索引,建议在需要优化查询速度的时候使用。</li>\n</ul>\n<h1 id=\"增\"><a href=\"#增\" class=\"headerlink\" title=\"增\"></a>增</h1><p><font color=\"red\">如果实体类使用字段@PrimaryKey注解的话需要注意的是realm.createObject(Book.class,keyValue);需要同时传入keyValue且是唯一的,如果值已经存在,此时会发生io.realm.exceptions.RealmPrimaryKeyConstraintException: Value already exists: 1错误,需要处理</font></p>\n<ul>\n<li><p>新增数据</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\">realm.beginTransaction();</div><div class=\"line\">Book book = realm.createObject(Book.class);</div><div class=\"line\">book.setBookName(<span class=\"string\">\"我的第一本书\"</span>);</div><div class=\"line\">book.setBookPrice(20);</div><div class=\"line\">//这里需要注意,对于多对多或者一对多的关系的话必须要先创建realm.createObject(XXX.class);</div><div class=\"line\">BookDirectory bookDirectory = realm.createObject(BookDirectory.class);</div><div class=\"line\">bookDirectory.setName(<span class=\"string\">\"简介\"</span>);</div><div class=\"line\">bookDirectory.setDescribe(<span class=\"string\">\"这本是的书名叫《我的第一本书》\"</span>);</div><div class=\"line\">RealmList<BookDirectory> directories = new RealmList<>();</div><div class=\"line\">directories.add(bookDirectory);</div><div class=\"line\">book.setDirectorys(directories);</div><div class=\"line\">realm.commitTransaction();</div></pre></td></tr></table></figure>\n</li>\n<li><p>使用事务块增加数据</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div></pre></td><td class=\"code\"><pre><div class=\"line\">final Book book = new Book();</div><div class=\"line\">book.setBookName(<span class=\"string\">\"我的第二本书\"</span>);</div><div class=\"line\">book.setBookPrice(40);</div><div class=\"line\">BookDirectory bookDirectory = new BookDirectory();</div><div class=\"line\">bookDirectory.setName(<span class=\"string\">\"简介\"</span>);</div><div class=\"line\">bookDirectory.setDescribe(<span class=\"string\">\"这本是的书名叫《我的第二本书》\"</span>);</div><div class=\"line\">RealmList<BookDirectory> directories = new RealmList<>();</div><div class=\"line\">directories.add(bookDirectory);</div><div class=\"line\">book.setDirectorys(directories);</div><div class=\"line\"> realm.executeTransaction(new Realm.<span class=\"function\"><span class=\"title\">Transaction</span></span>() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void execute(Realm realm) {</div><div class=\"line\"> realm.copyToRealm(book);</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<h1 id=\"删\"><a href=\"#删\" class=\"headerlink\" title=\"删\"></a>删</h1><ul>\n<li><p>删除所有数据</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">final RealmResults<Book> books = realm.where(Book.class).findAll();</div><div class=\"line\">realm.executeTransaction(new Realm.<span class=\"function\"><span class=\"title\">Transaction</span></span>() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void execute(Realm realm) {</div><div class=\"line\"> //删除所有数据</div><div class=\"line\"> books.deleteAllFromRealm();</div><div class=\"line\"> Toast.makeText(MainActivity.this, <span class=\"string\">\"删除成功\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\"> }</div><div class=\"line\"> });</div></pre></td></tr></table></figure>\n</li>\n<li><p>删除指定item数据</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">Book book = books.get(0);</div><div class=\"line\">book.deleteFromRealm();</div></pre></td></tr></table></figure>\n</li>\n<li><p>删除第一个数据</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">books.deleteFirstFromRealm();</div></pre></td></tr></table></figure>\n</li>\n<li><p>删除最后一个数据</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">books.deleteLastFromRealm();</div></pre></td></tr></table></figure>\n</li>\n<li><p>删除position为0的数据</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">books.deleteFromRealm(0);</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<h1 id=\"查\"><a href=\"#查\" class=\"headerlink\" title=\"查\"></a>查</h1><ul>\n<li><p>查询全部记录</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\">RealmResults<Book> books = realm.where(Book.class).findAll();</div><div class=\"line\">List<Book> bookList = realm.copyFromRealm(books);//将查询结果转为list对象</div><div class=\"line\">Toast.makeText(this, <span class=\"string\">\"共查询到\"</span> + bookList.size() + <span class=\"string\">\"条记录\"</span>, Toast.LENGTH_SHORT).show();</div></pre></td></tr></table></figure>\n</li>\n<li><p>条件查询,多条件查询则在后面追加equalTo即可</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">Book book = realm.where(Book.class).equalTo(<span class=\"string\">\"bookName\"</span>, <span class=\"string\">\"我的第一本书\"</span>).findFirst();</div><div class=\"line\"><span class=\"keyword\">if</span> (book != null) {</div><div class=\"line\"> book = realm.copyFromRealm(book);//转换为可直接直接调用的对象</div><div class=\"line\"> Toast.makeText(this, <span class=\"string\">\"查询书名为“我的第一本书”找到了\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\">} <span class=\"keyword\">else</span> {</div><div class=\"line\"> Toast.makeText(this, <span class=\"string\">\"查询书名为“我的第一本书”找不到,试试先添加纪录再找\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n<li><p>对查询结果进行排序</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">RealmResults<Book> books = realm.where(Book.class).findAll();</div><div class=\"line\">//增序排序</div><div class=\"line\">books = books.sort(<span class=\"string\">\"bookPrice\"</span>);</div><div class=\"line\">//降序排序</div><div class=\"line\">//books = books.sort(<span class=\"string\">\"bookPrice\"</span>, Sort.DESCENDING);</div><div class=\"line\">List<Book> bookList = realm.copyFromRealm(books);</div><div class=\"line\">Toast.makeText(this, <span class=\"string\">\"查询到了\"</span> + bookList.size() + <span class=\"string\">\"条数据,已排序\"</span>, Toast.LENGTH_SHORT).show();</div></pre></td></tr></table></figure>\n</li>\n<li><p>查询所有书的平均价格</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">realm.where(Book.class).findAll().average(<span class=\"string\">\"bookPrice\"</span>);</div></pre></td></tr></table></figure>\n</li>\n<li><p>查询所有书的总价格</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">realm.where(Book.class).findAll().sum(<span class=\"string\">\"bookPrice\"</span>);</div></pre></td></tr></table></figure>\n</li>\n<li><p>查询价格最高的书</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">realm.where(Book.class).findAll().max(<span class=\"string\">\"bookPrice\"</span>);</div></pre></td></tr></table></figure>\n</li>\n<li><p>查询价格最低的书</p>\n<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">realm.where(Book.class).findAll().min(<span class=\"string\">\"bookPrice\"</span>);</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<p>其它查询自行扩展</p>\n<h1 id=\"改\"><a href=\"#改\" class=\"headerlink\" title=\"改\"></a>改</h1><ul>\n<li>更新指定数据<figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div></pre></td><td class=\"code\"><pre><div class=\"line\">Book book = realm.where(Book.class).equalTo(<span class=\"string\">\"bookName\"</span>, <span class=\"string\">\"我的第一本书\"</span>).findFirst();</div><div class=\"line\"><span class=\"keyword\">if</span> (book != null) {</div><div class=\"line\"> realm.beginTransaction();</div><div class=\"line\"> book.setBookName(<span class=\"string\">\"我的第N本书\"</span>);</div><div class=\"line\"> realm.commitTransaction();</div><div class=\"line\"> Toast.makeText(this, <span class=\"string\">\"更新成功\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\">} <span class=\"keyword\">else</span> {</div><div class=\"line\"> Toast.makeText(this, <span class=\"string\">\"查询书名为“我的第一本书”找不到,试试先添加纪录再找\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<h1 id=\"异步操作\"><a href=\"#异步操作\" class=\"headerlink\" title=\"异步操作\"></a>异步操作</h1><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div></pre></td><td class=\"code\"><pre><div class=\"line\">final Book book = new Book();</div><div class=\"line\">book.setBookName(<span class=\"string\">\"我的第三本书\"</span>);</div><div class=\"line\">book.setBookPrice(60);</div><div class=\"line\">BookDirectory bookDirectory = new BookDirectory();</div><div class=\"line\">bookDirectory.setName(<span class=\"string\">\"简介\"</span>);</div><div class=\"line\">bookDirectory.setDescribe(<span class=\"string\">\"这本是的书名叫《我的第三本书》\"</span>);</div><div class=\"line\">RealmList<BookDirectory> directories = new RealmList<>();</div><div class=\"line\">directories.add(bookDirectory);</div><div class=\"line\">book.setDirectorys(directories);</div><div class=\"line\">addTask = realm.executeTransactionAsync(new Realm.<span class=\"function\"><span class=\"title\">Transaction</span></span>() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void execute(Realm realm) {</div><div class=\"line\"> realm.copyToRealm(book);</div><div class=\"line\"> }</div><div class=\"line\">}, new Realm.Transaction.<span class=\"function\"><span class=\"title\">OnSuccess</span></span>() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void <span class=\"function\"><span class=\"title\">onSuccess</span></span>() {</div><div class=\"line\"> Toast.makeText(MainActivity.this, <span class=\"string\">\"添加成功\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\"> }</div><div class=\"line\">}, new Realm.Transaction.<span class=\"function\"><span class=\"title\">OnError</span></span>() {</div><div class=\"line\"> @Override</div><div class=\"line\"> public void onError(Throwable error) {</div><div class=\"line\"> Toast.makeText(MainActivity.this, <span class=\"string\">\"添加失败\"</span>, Toast.LENGTH_SHORT).show();</div><div class=\"line\"> }</div><div class=\"line\">});</div></pre></td></tr></table></figure>\n<p>其它删除、更新、修改操作类似<br>最后记得在onDestroy中close和取消掉异步任务:如下代码:<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">@Override</div><div class=\"line\">public void <span class=\"function\"><span class=\"title\">onDestroy</span></span>() {</div><div class=\"line\"> super.onDestroy();</div><div class=\"line\"> <span class=\"keyword\">if</span> (addTask != null && addTask.isCancelled()) {</div><div class=\"line\"> addTask.cancel();//取消掉异步任务</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">if</span> (realm != null) {</div><div class=\"line\"> realm.close();</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<h1 id=\"Demo\"><a href=\"#Demo\" class=\"headerlink\" title=\"Demo\"></a>Demo</h1><p>最后附上<a href=\"https://github.com/wdh-1025/AndroidRealmDB\" target=\"_blank\" rel=\"external\">demo</a>地址,欢迎Star、Fork<br><a href=\"https://realm.io/docs/java/latest/\" target=\"_blank\" rel=\"external\">官方文档</a></p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p>OK 大功告成,总体使用还是比SQLite舒爽一点,就是刚开始接触的话坑比较多,网上找找答案看看官方文档描述就解决了。</p>\n"},{"title":"app增量更新","url":"http://www.68blog.com/2016/11/06/4/","content":"<h1 id=\"写在前面\"><a href=\"#写在前面\" class=\"headerlink\" title=\"写在前面\"></a>写在前面</h1><p><font color=\"red\">本文运行环境为windows,其他运行环境请自行百度</font><br>本文带你一起实现android增量更新(并非热修复),主要都是一些工具的实现,权当记录,也方便以后自己查看;<br>首先什么是增量更新?<br>顾名思义,就是只更新增加部分,一个app有几百M,但是实际修改只有几M或者更小,那么我们就只要下载差异部分进行合成更新即可,这样可为用户减少很大的流量流失。</p>\n<p>把整个流程细化为几个关键点:</p>\n<ul>\n<li>服务器生成差异文件</li>\n<li>app提取当前安装应用并与差异文件进行合并,生成新的apk</li>\n<li>调用系统安装</li>\n</ul>\n<p>只有第二点稍微有点难度,但是已经有工具帮我们实现了,SO…难度=0;</p>\n<h1 id=\"服务器生成差异文件\"><a href=\"#服务器生成差异文件\" class=\"headerlink\" title=\"服务器生成差异文件\"></a>服务器生成差异文件</h1><p><a href=\"http://download.csdn.net/detail/z191726501/9651809\" target=\"_blank\" rel=\"external\">下载bsdiff和bspacth</a>并切换到对应路径<br>准备两个apk,old.apk和new.apk(old.apk为旧的apk,new为更新后的apk)</p>\n<ul>\n<li>生成增量文件<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">bsdiff old.apk new.apk patch.patch</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<p>这样就生成了一个增量文件patch.patch</p>\n<ul>\n<li>增量文件patch.patch和old.apk合并成新的apk<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">bspatch old.apk new2.apk patch.patch</div></pre></td></tr></table></figure>\n</li>\n</ul>\n<p>查看文件md5值可以证明两个文件是否一样<br>目前为止服务端已经完成生成增量文件</p>\n<h1 id=\"客户端合成应用\"><a href=\"#客户端合成应用\" class=\"headerlink\" title=\"客户端合成应用\"></a>客户端合成应用</h1><p><font color=\"red\">需要设置ndk运行环境</font><br>接下来我们要提取本地应用apk,这个相对简单,代码如下:<br><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">public static String extract(Context context) {</div><div class=\"line\"> context = context.getApplicationContext();</div><div class=\"line\"> ApplicationInfo applicationInfo = context.getApplicationInfo();</div><div class=\"line\"> String apkPath = applicationInfo.sourceDir;</div><div class=\"line\"> return apkPath;</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>制作bspatch so,新建类,代码如下:<br><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">public class BsPatch {</div><div class=\"line\"> static {</div><div class=\"line\"> System.loadLibrary("bsdiff");</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> public static native int bspatch(String oldApk, String newApk, String patch);</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>同时需要在module的build.gradle下面增加:<br><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">android {</div><div class=\"line\">\t...</div><div class=\"line\">\tdefaultConfig {</div><div class=\"line\"> \t\tndk {</div><div class=\"line\"> \t\tmoduleName = 'bsdiff'</div><div class=\"line\"> \t\t}</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>接下来需要编写C代码了,当然并非自己编写,bsdiff已经提供给我们了,把之前下载的bsdiff中的bspatch.c拷贝进去并新增一个方法</p>\n<p><font color=\"red\">注意方法名“JNICALL Java_com_addupdate_BsPatch_bspatch”,命名是有规则的,相对简单</font><br><figure class=\"highlight c\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\">JNIEXPORT jint JNICALL <span class=\"title\">Java_com_addupdate_BsPatch_bspatch</span></span></div><div class=\"line\"> <span class=\"params\">(JNIEnv *env, jclass cls,</span></div><div class=\"line\"> jstring old, jstring <span class=\"keyword\">new</span>, jstring patch){</div><div class=\"line\"> <span class=\"keyword\">int</span> argc = <span class=\"number\">4</span>;</div><div class=\"line\"> <span class=\"keyword\">char</span> * argv[argc];</div><div class=\"line\"> argv[<span class=\"number\">0</span>] = <span class=\"string\">\"bspatch\"</span>;</div><div class=\"line\"> argv[<span class=\"number\">1</span>] = (<span class=\"keyword\">char</span>*) ((*env)->GetStringUTFChars(env, old, <span class=\"number\">0</span>));</div><div class=\"line\"> argv[<span class=\"number\">2</span>] = (<span class=\"keyword\">char</span>*) ((*env)->GetStringUTFChars(env, <span class=\"keyword\">new</span>, <span class=\"number\">0</span>));</div><div class=\"line\"> argv[<span class=\"number\">3</span>] = (<span class=\"keyword\">char</span>*) ((*env)->GetStringUTFChars(env, patch, <span class=\"number\">0</span>));</div><div class=\"line\"> <span class=\"keyword\">int</span> ret = patchMethod(argc, argv);</div><div class=\"line\"> (*env)->ReleaseStringUTFChars(env, old, argv[<span class=\"number\">1</span>]);</div><div class=\"line\"> (*env)->ReleaseStringUTFChars(env, <span class=\"keyword\">new</span>, argv[<span class=\"number\">2</span>]);</div><div class=\"line\"> (*env)->ReleaseStringUTFChars(env, patch, argv[<span class=\"number\">3</span>]);</div><div class=\"line\"> <span class=\"keyword\">return</span> ret;</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>并把main方法改为patchMethod,依赖<a href=\"http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz\" target=\"_blank\" rel=\"external\">bzlib</a>,并把其中的.h和.c文件提取出来,复制到module的app/main/jni,下面会给出源码和编译好的.so文件。<br>如果发生下面错误:<br>Error:(70) multiple definition of `main’<br>提示main方法重复定义了,在出错信息中会给出哪些类中包含main方法,可以直接将这些类中的main方法直接删除。<br>再次编译就OK啦~~~</p>\n<h1 id=\"app调用\"><a href=\"#app调用\" class=\"headerlink\" title=\"app调用\"></a>app调用</h1><p>准备两个apk:<br>old.apk new.apk<br>然后服务器生成一个patch包,下面代码中的patch.patch:</p>\n<p>将old.apk安装,然后将new.apk以及patch.patch放置到存储卡(测试阶段,发布阶段需从服务器下载patch包);<br>最后在app需要更新的地方调用增量更新:<br><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div></pre></td><td class=\"code\"><pre><div class=\"line\">private void doBspatch() {</div><div class=\"line\"> final File destApk = new File(Environment.getExternalStorageDirectory(), "dest.apk");</div><div class=\"line\"> final File patch = new File(Environment.getExternalStorageDirectory(), "patch.patch");</div><div class=\"line\"> BsPatch.bspatch(ApkExtract.extract(this),</div><div class=\"line\"> destApk.getAbsolutePath(),</div><div class=\"line\"> patch.getAbsolutePath());</div><div class=\"line\"> if (destApk.exists()) {</div><div class=\"line\"> ApkExtract.install(this, destApk.getAbsolutePath());</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>合成新的apk完成后调用系统安装,代码如下:<br><figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">public static void install(Context context, String apkPath) {</div><div class=\"line\"> Intent i = new Intent(Intent.ACTION_VIEW);</div><div class=\"line\"> i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);</div><div class=\"line\"> i.setDataAndType(Uri.fromFile(new File(apkPath)),</div><div class=\"line\"> "application/vnd.android.package-archive");</div><div class=\"line\"> context.startActivity(i);</div><div class=\"line\"> android.os.Process.killProcess(android.os.Process.myPid());</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p><a href=\"https://github.com/wdh-1025/android-addupdate\" target=\"_blank\" rel=\"external\">Demo地址</a></p>\n<h1 id=\"总结\"><a href=\"#总结\" class=\"headerlink\" title=\"总结\"></a>总结</h1><p><a href=\"https://github.com/kingwang666/AppAddUpdate\" target=\"_blank\" rel=\"external\">AppAddUpdate</a>是别人封装好的,可以直接使用,但是建议可以自己跑一遍,不然将会失去很多学习机会,过程中或多或少会遇到很多坑,跨过去就好了…</p>\n"},{"title":"蓝牙BLE android6.0的坑","url":"http://www.68blog.com/2016/11/03/1/","content":"<p>昨天写好蓝牙调试工具,因为一直拿着5.1的机子进行测试,没发现问题,到客户面前演示的时候,客户拿着6.0的手机安装测试,结果,蒙逼了,android6.0竟然扫不到设备,苦逼了好久,OK,开始一步步审查代码。发现<strong>startLeScan</strong>、<strong>stopLeScan</strong>这两个方法被谷歌弃用了,好吧,寻找替代的方法,结果设置参数过于麻烦。</p>\n<p>最后在“权限”上下手,想到以前跟同事说过扫描蓝牙竟然要GPS定位权限,不肥话,测试之,问题解决…</p>\n<p>因为android6.0在安全权限上做了较大的改变,所以搜索蓝牙需要在AndroidManifest.xml上添加该权限并确保你获取了该权限</p>\n<h3 id=\"Permission\"><a href=\"#Permission\" class=\"headerlink\" title=\"Permission\"></a>Permission</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">uses-permission android:name=<span class=\"string\">\"android.permission.ACCESS_COARSE_LOCATION\"</span></div></pre></td></tr></table></figure>\n"},{"title":"PHP图片批量上传","url":"http://www.68blog.com/2015/12/07/3/","content":"<h1 id=\"总结一下PHP上传图片。\"><a href=\"#总结一下PHP上传图片。\" class=\"headerlink\" title=\"总结一下PHP上传图片。\"></a>总结一下PHP上传图片。</h1><p>上传图片原理:首先判断文件类型是否为图片格式,若是则上传文件,然后重命名文件(一般都是避免上传文件重名,现在基本上都是以为时间来命名),接着把文件上传到指定目录,成功上传后输出上传图片的预览。<br>1.首先我们开始判断文件类型是否为图片类型<br>用到的函数<br><figure class=\"highlight php\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\">strrchr:查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。</div><div class=\"line\">substr: 取部份字符串。</div><div class=\"line\">$HTTP_POST_FILES[<span class=\"string\">'file'</span>][<span class=\"string\">'name'</span>]:获取当前上传的文件全称。</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>图片类型就是“.”后面的字符(比如:一个文件名称为XXX.JPG 那么它的类型就是“.”后面的JPG)。 我们可以用PHP中的函数来截取上传者文件名字的。我们来写个获取文件类型的函数<br><figure class=\"highlight php\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"meta\"><?</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">type</span><span class=\"params\">()</span></span></div><div class=\"line\">{</div><div class=\"line\"><span class=\"keyword\">return</span> substr(strrchr($HTTP_POST_FILES[<span class=\"string\">'file'</span>][<span class=\"string\">'name'</span>],<span class=\"string\">'.'</span>),<span class=\"number\">1</span>);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"meta\">?></span></div></pre></td></tr></table></figure></p>\n<p>2.若是则上传文件,然后重命名文件<br>用到的函数<br><figure class=\"highlight php\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">{</div><div class=\"line\">strtolower:把字符串的字母全部转换为小写字母.</div><div class=\"line\">in_array: 函数在数组中搜索给定的值。</div><div class=\"line\">implode:函数把数组元素组合为一个字符串</div><div class=\"line\">random:随机生成的数</div><div class=\"line\">$_FILES[<span class=\"string\">'userfile'</span>][<span class=\"string\">'name'</span>]:上传文件名称</div><div class=\"line\">$uploaddir:自己定义的变量。比如在同一个文件夹里面,你想把上传的文件放到这个文件夹的FILE文件夹下,你可以这样定义$uploaddir=<span class=\"string\">\"./file/\"</span>;注意写法</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>这边会出现很多问题,第一先写一个能上传类型的数组。第二判断文件合法性。第三给文件重名。*(这边判断文件大小就不写了)<br>先定义允许上传文件的类型数组:$type=array(“jpg”,”gif”,”bmp”,”jpeg”,”png”);<br>第二用一个IF。。else。。写一个判断文件合法性的控制流语句。<br><figure class=\"highlight php\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">if</span>(!in_arry(strtolower(type()),$type))<span class=\"comment\">//如果不存在能上传的类型</span></div><div class=\"line\">{</div><div class=\"line\"> $text=implode(<span class=\"string\">'.'</span>,$type);</div><div class=\"line\"> <span class=\"keyword\">echo</span> <span class=\"string\">\"您只能上传以下类型文件: \"</span>.$text.<span class=\"string\">\"<br>\"</span>;</div><div class=\"line\">}</div></pre></td></tr></table></figure></p>\n<p>下面就是给他们重新命名了</p>\n"},{"title":"在Windows下搭建React Native Android开发环境","url":"http://www.68blog.com/2015/11/18/2/","content":"<h2 id=\"安装JDK\"><a href=\"#安装JDK\" class=\"headerlink\" title=\"安装JDK\"></a>安装JDK</h2><p>从<a href=\"http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html\" target=\"_blank\" rel=\"external\">Java官网</a>下载JDK并安装。请注意选择x86还是x64版本。<br>推荐将JDK的bin目录加入系统PATH环境变量。</p>\n<h2 id=\"安装Android-SDK\"><a href=\"#安装Android-SDK\" class=\"headerlink\" title=\"安装Android SDK\"></a>安装Android SDK</h2><p>可以单独安装Android SDK,也可以通过Eclipse ADT或者Android Studio一并安装。推荐使用Android Studio,以下说明会默认以Android Studio的方式说明。请注意选择x86还是x64版本。<br>为了加速下载,推荐从<a href=\"http://androiddevtools.cn/\" target=\"_blank\" rel=\"external\">AndroidDevTools</a>下载。<br>然后进入SDKManager(可通过Android Studio菜单Tools-Android-SDK Manager),确保以下项目已经安装并更新到最新:</p>\n<ul>\n<li><p>Tools/Android SDK Tools (24.3.3)</p>\n</li>\n<li><p>Tools/Android SDK Platform-tools (22)</p>\n</li>\n<li><p>Tools/Android SDK Build-tools (23.0.1)</p>\n</li>\n<li><p>Android 6.0 (API 23)/SDK Platform (1)</p>\n</li>\n<li><p>Extras/Android Support Library(23.0.1)<br>推荐使用腾讯Bugly的镜像加速下载。<a href=\"http://android-mirror.bugly.qq.com:8080/include/usage.html\" target=\"_blank\" rel=\"external\">查看说明</a><br>推荐将SDK的platform-tools子目录加入系统PATH环境变量。</p>\n</li>\n</ul>\n<h2 id=\"安装C-环境\"><a href=\"#安装C-环境\" class=\"headerlink\" title=\"安装C++环境\"></a>安装C++环境</h2><p>推荐从<a href=\"http://msdn.itellyou.cn/\" target=\"_blank\" rel=\"external\">itellyou</a>下载并安装Visual Studio 2013或2015。也可选择Windows SDK、cygwin或mingw等其他C++环境。编译node.js的C++模块时需要用到。</p>\n<h2 id=\"安装node-js\"><a href=\"#安装node-js\" class=\"headerlink\" title=\"安装node.js\"></a>安装node.js</h2><p>从官网下载node.js的官方4.1版本或更高版本。<br>安装react-native命令行工具<br>官方的安装方法是<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">npm install -g react-native-cli</div></pre></td></tr></table></figure></p>\n<p>但是由于npm上的版本在windows下存在BUG,因此需要安装github上的master支线,否则会在下一步骤报以下错误:<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">This will walk you through creating a new React Native project <span class=\"keyword\">in</span> *** events.js:141 throw er; // Unhandled <span class=\"string\">'error'</span> event ^ Error: spawn npm ENOENT at exports._errnoException (util.js:837:11) at Process.ChildProcess._handle.onexit (internal/child_process.js:178:32) at onErrorNT (internal/child_process.js:344:16) at <span class=\"keyword\">do</span>NTCallback2 (node.js:429:9) at process._tickCallback (node.js:343:17) at Function.Module.runMain (module.js:477:11) at startup (node.js:117:18) at node.js:951:3</div></pre></td></tr></table></figure></p>\n<p>如果您看到本文时0.12已经发布,那很可能直接输入上面的命令就行了。如果0.12还没有发布,请进行以下步骤:<br>在React Native的Github页面右侧点击Download ZIP,下载后解压,并执行以下代码:<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"built_in\">cd</span> **解压的目录** <span class=\"built_in\">cd</span> react-native-cli npm install -g</div></pre></td></tr></table></figure></p>\n<h2 id=\"创建项目\"><a href=\"#创建项目\" class=\"headerlink\" title=\"创建项目\"></a>创建项目</h2><p>进入你的工作目录,运行<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">react-native init MyProject</div></pre></td></tr></table></figure></p>\n<p>并耐心等待数分钟。</p>\n<h2 id=\"运行packager\"><a href=\"#运行packager\" class=\"headerlink\" title=\"运行packager\"></a>运行packager</h2><p>首先要修复package在windows下的两处BUG。</p>\n<p>1、参考这个<a href=\"https://github.com/hzerica/react-native/commits/master-pr-5\" target=\"_blank\" rel=\"external\">commit</a>,在node_modules/react-native/packager/react-packager/src/DependencyResolver/Module.js的getName()方法中,将<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"built_in\">return</span> path.join(name, path.relative(p.root, this.path));</div></pre></td></tr></table></figure></p>\n<p>修改为<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"built_in\">return</span> path.join(name, path.relative(p.root, this.path)).replace(/\\\\/g, <span class=\"string\">'/'</span>);</div></pre></td></tr></table></figure></p>\n<p>注意,如果你在修改此行代码之前运行过packager,那你可能需要去C:\\Users\\你的用户名\\AppData\\Local\\Temp中找到并删除所有 react-packager-cache 开头的文件。</p>\n<p>2、参考这个commit,在node_modules/react-native/packager/react-packager/src/DependencyResolver/DependencyGraph/ResolutionRequest.js的_resolveNodeDependency(fromModule, toModuleName)方法中,将<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">for</span> (<span class=\"built_in\">let</span> currDir = path.dirname(fromModule.path); currDir !== <span class=\"string\">'/'</span>; currDir = path.dirname(currDir)) {</div></pre></td></tr></table></figure></p>\n<p>修改为<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">for</span> (<span class=\"built_in\">let</span> currDir = path.dirname(fromModule.path); path.dirname(currDir) != currDir;</div></pre></td></tr></table></figure></p>\n<p>随后可以运行packager。<br>如果你有cygwin,可以在cygwin环境中进入工程目录,运行<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">npm start</div></pre></td></tr></table></figure></p>\n<p>如果没有cygwin或不在cygwin环境中,可以进入工程目录,运行<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">node node_modules\\react-native\\packager\\packager.js</div></pre></td></tr></table></figure></p>\n<p>可以用浏览器访问<a href=\"http://localhost:8081/index.android.bundle?platform=android\" target=\"_blank\" rel=\"external\">http://localhost:8081/index.android.bundle?platform=android</a>看看是否可以看到打包后的脚本。第一次访问通常需要十几秒,并且在packager的命令行可以看到进度条。如果迟迟看不到进度条,请检查上面的修改是否已经做到。</p>\n<h2 id=\"运行模拟器\"><a href=\"#运行模拟器\" class=\"headerlink\" title=\"运行模拟器\"></a>运行模拟器</h2><p>推荐使用BlueStacks不过要小心它推送的广告和垃圾应用。<br>如果有真机,可以不必运行模拟器,要配置好驱动,使得adb devices可以看到对应的设备。</p>\n<h2 id=\"安卓运行\"><a href=\"#安卓运行\" class=\"headerlink\" title=\"安卓运行\"></a>安卓运行</h2><p>保持packager开启,另外打开一个命令行窗口,然后在工程目录下运行<br><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">react-native run-android</div></pre></td></tr></table></figure></p>\n<p>首次运行需要等待数分钟并从网上下载gradle依赖。</p>\n<p>运行完毕后可以在模拟器或真机上看到应用自动启动了。</p>\n<p>如果gradle依赖下载出现报错,请多试几次,或者设置VPN加速。</p>\n<p>如果apk安装运行出现报错,请检查platform-tools是否已经设到了PATH环境变量中,运行adb devices能否看到设备。</p>\n<p>至此,应该能看到APP运行,并报错 Unable to download JS bundle</p>\n<p>摇晃设备或按Menu键(Bluestacks模拟器按键盘上的菜单键,通常在右Ctrl的左边 或者左Windows键旁边),可以打开调试菜单,点击Dev Settings,选Debug server host for device,输入你的局域网IP,再按back键返回,再按Menu键,在调试菜单中选择Reload JS,就应该可以看到运行的结果了。</p>\n<h2 id=\"安卓调试\"><a href=\"#安卓调试\" class=\"headerlink\" title=\"安卓调试\"></a>安卓调试</h2><p>目前Windows下无法自动打开chrome进行调试,所以手动打开chrome,访问如下地址:<a href=\"http://localhost:8081/debugger-ui\" target=\"_blank\" rel=\"external\">http://localhost:8081/debugger-ui</a> 即可。</p>\n<p>=====================================================================</p>\n<p>已按该教程搭建完成。以下是截图</p>\n<p><img src=\"http://wdh1025.ae124.zuji-08.com/upload/images/rn.jpg\" alt=\"截图\"></p>\n"},{"title":"因网站服务器迁移,文章数据暂未同步迁移","url":"http://www.68blog.com/2015/10/17/0/","content":""},{"title":"about","url":"http://www.68blog.com/about/index.html","content":""},{"title":"link","url":"http://www.68blog.com/link/index.html","content":""},{"title":"index","url":"http://www.68blog.com/index/index.html","content":""},{"title":"search","url":"http://www.68blog.com/search/index.html","content":""},{"title":"tag","url":"http://www.68blog.com/tag/index.html","content":""}]