blob: deeeeae5d15b17358bd63304ad01a9de1b155819 [file] [log] [blame]
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>背景介绍 | WEEX</title>
<meta name="description" content="Weex">
<link rel="icon" href="//gw.alicdn.com/tps/TB1XNqxPXXXXXcSXVXXXXXXXXXX-64-63.png">
<script src="//g.alicdn.com/alilog/mlog/aplus_v2.js"></script>
<meta name="data-spm" dataSpmProtocol="i" content="a2c7j">
<meta name="aplus-ajax" content="chksum">
<meta name="aplus-waiting" content="MAN">
<meta name="google-site-verification" content="FbH8DPHpxdDJlfkKLKXuXWOu69DI8ZRRP8O2Phg8UKw">
<meta name="baidu-site-verification" content="WRr1iWvsYK">
<link rel="preload" href="/assets/css/styles.0ff943f0.css" as="style"><link rel="preload" href="/assets/js/app.0ff943f0.js" as="script"><link rel="preload" href="/assets/js/115.d7e38c3b.js" as="script"><link rel="prefetch" href="/assets/css/1.styles.aa72e838.css"><link rel="prefetch" href="/assets/css/10.styles.1fff5b86.css"><link rel="prefetch" href="/assets/css/11.styles.a03faa50.css"><link rel="prefetch" href="/assets/css/2.styles.fc5d9892.css"><link rel="prefetch" href="/assets/css/21.styles.9ebad2b1.css"><link rel="prefetch" href="/assets/css/3.styles.6b94323a.css"><link rel="prefetch" href="/assets/css/36.styles.6dbb9d8c.css"><link rel="prefetch" href="/assets/css/4.styles.706a5607.css"><link rel="prefetch" href="/assets/css/7.styles.469d3b64.css"><link rel="prefetch" href="/assets/css/8.styles.b36167bf.css"><link rel="prefetch" href="/assets/css/9.styles.5bed6ebe.css"><link rel="prefetch" href="/assets/js/10.1fff5b86.js"><link rel="prefetch" href="/assets/js/100.09076a87.js"><link rel="prefetch" href="/assets/js/101.71fa3538.js"><link rel="prefetch" href="/assets/js/102.8a9926d6.js"><link rel="prefetch" href="/assets/js/103.d6c3649e.js"><link rel="prefetch" href="/assets/js/104.adb2425b.js"><link rel="prefetch" href="/assets/js/105.a063ca34.js"><link rel="prefetch" href="/assets/js/106.620e227f.js"><link rel="prefetch" href="/assets/js/107.1c97d156.js"><link rel="prefetch" href="/assets/js/108.d1f236a9.js"><link rel="prefetch" href="/assets/js/109.10a909cc.js"><link rel="prefetch" href="/assets/js/11.a03faa50.js"><link rel="prefetch" href="/assets/js/110.6f9200c8.js"><link rel="prefetch" href="/assets/js/111.9c1831b3.js"><link rel="prefetch" href="/assets/js/112.e5c0d546.js"><link rel="prefetch" href="/assets/js/113.b1c17feb.js"><link rel="prefetch" href="/assets/js/114.c24b95ed.js"><link rel="prefetch" href="/assets/js/116.1aaa95ab.js"><link rel="prefetch" href="/assets/js/117.1a9e5539.js"><link rel="prefetch" href="/assets/js/118.8d915477.js"><link rel="prefetch" href="/assets/js/119.77f0a126.js"><link rel="prefetch" href="/assets/js/12.16a9b730.js"><link rel="prefetch" href="/assets/js/120.3cf0ba10.js"><link rel="prefetch" href="/assets/js/121.47fefbf1.js"><link rel="prefetch" href="/assets/js/122.3dd022e8.js"><link rel="prefetch" href="/assets/js/123.84abc63f.js"><link rel="prefetch" href="/assets/js/124.2568e233.js"><link rel="prefetch" href="/assets/js/125.5b665f24.js"><link rel="prefetch" href="/assets/js/126.25b58a0a.js"><link rel="prefetch" href="/assets/js/127.d62a58c6.js"><link rel="prefetch" href="/assets/js/128.e5774a02.js"><link rel="prefetch" href="/assets/js/129.9a813c06.js"><link rel="prefetch" href="/assets/js/13.f8bde866.js"><link rel="prefetch" href="/assets/js/130.edddc316.js"><link rel="prefetch" href="/assets/js/131.760aa65c.js"><link rel="prefetch" href="/assets/js/132.559d5ba7.js"><link rel="prefetch" href="/assets/js/133.cbdd35c7.js"><link rel="prefetch" href="/assets/js/134.c02d92e1.js"><link rel="prefetch" href="/assets/js/135.e6d5496a.js"><link rel="prefetch" href="/assets/js/136.8826af60.js"><link rel="prefetch" href="/assets/js/137.28b4573d.js"><link rel="prefetch" href="/assets/js/138.d370fc15.js"><link rel="prefetch" href="/assets/js/139.8d9150fc.js"><link rel="prefetch" href="/assets/js/14.a98602cc.js"><link rel="prefetch" href="/assets/js/140.f0a9b5e1.js"><link rel="prefetch" href="/assets/js/141.297fa6fe.js"><link rel="prefetch" href="/assets/js/142.82bbcbaa.js"><link rel="prefetch" href="/assets/js/143.2d1ed3b2.js"><link rel="prefetch" href="/assets/js/144.69a9bc6a.js"><link rel="prefetch" href="/assets/js/145.74d52c12.js"><link rel="prefetch" href="/assets/js/146.12ecdaf4.js"><link rel="prefetch" href="/assets/js/147.daad4b96.js"><link rel="prefetch" href="/assets/js/148.bb356182.js"><link rel="prefetch" href="/assets/js/149.56fdaace.js"><link rel="prefetch" href="/assets/js/15.ea6e5024.js"><link rel="prefetch" href="/assets/js/150.ee9c4994.js"><link rel="prefetch" href="/assets/js/151.2feae618.js"><link rel="prefetch" href="/assets/js/152.c7703521.js"><link rel="prefetch" href="/assets/js/153.3b555eab.js"><link rel="prefetch" href="/assets/js/154.c6329253.js"><link rel="prefetch" href="/assets/js/155.334c4ea4.js"><link rel="prefetch" href="/assets/js/156.1a29657f.js"><link rel="prefetch" href="/assets/js/157.ba8f07bc.js"><link rel="prefetch" href="/assets/js/158.a60a60ba.js"><link rel="prefetch" href="/assets/js/159.9ce96d49.js"><link rel="prefetch" href="/assets/js/16.14acc638.js"><link rel="prefetch" href="/assets/js/160.2a970224.js"><link rel="prefetch" href="/assets/js/161.a26e2b53.js"><link rel="prefetch" href="/assets/js/162.73535662.js"><link rel="prefetch" href="/assets/js/163.7518a0a5.js"><link rel="prefetch" href="/assets/js/164.17367778.js"><link rel="prefetch" href="/assets/js/165.46c8f055.js"><link rel="prefetch" href="/assets/js/166.1cc22037.js"><link rel="prefetch" href="/assets/js/167.3fbcb5c6.js"><link rel="prefetch" href="/assets/js/168.a3f80f1e.js"><link rel="prefetch" href="/assets/js/169.a6565c29.js"><link rel="prefetch" href="/assets/js/17.d6f2f3b8.js"><link rel="prefetch" href="/assets/js/170.566ddeda.js"><link rel="prefetch" href="/assets/js/171.4fd97bee.js"><link rel="prefetch" href="/assets/js/172.5295c6b9.js"><link rel="prefetch" href="/assets/js/173.ff25fd05.js"><link rel="prefetch" href="/assets/js/174.22ea6a1b.js"><link rel="prefetch" href="/assets/js/175.c6a04367.js"><link rel="prefetch" href="/assets/js/176.d3810924.js"><link rel="prefetch" href="/assets/js/177.facd2802.js"><link rel="prefetch" href="/assets/js/178.f4c6fbe9.js"><link rel="prefetch" href="/assets/js/179.1a3a2c12.js"><link rel="prefetch" href="/assets/js/18.83f6b39a.js"><link rel="prefetch" href="/assets/js/180.b54c8e90.js"><link rel="prefetch" href="/assets/js/181.88495b4c.js"><link rel="prefetch" href="/assets/js/182.8341d23c.js"><link rel="prefetch" href="/assets/js/183.332bcfe2.js"><link rel="prefetch" href="/assets/js/184.d8996a56.js"><link rel="prefetch" href="/assets/js/185.b8584f07.js"><link rel="prefetch" href="/assets/js/186.fa89e23f.js"><link rel="prefetch" href="/assets/js/187.90340eeb.js"><link rel="prefetch" href="/assets/js/188.efe631f8.js"><link rel="prefetch" href="/assets/js/189.72897b1a.js"><link rel="prefetch" href="/assets/js/19.94f071c0.js"><link rel="prefetch" href="/assets/js/190.1ec691ee.js"><link rel="prefetch" href="/assets/js/2.fc5d9892.js"><link rel="prefetch" href="/assets/js/20.13f7bbff.js"><link rel="prefetch" href="/assets/js/21.9ebad2b1.js"><link rel="prefetch" href="/assets/js/22.764b643d.js"><link rel="prefetch" href="/assets/js/23.f533737e.js"><link rel="prefetch" href="/assets/js/24.4eaa533c.js"><link rel="prefetch" href="/assets/js/25.e9877e57.js"><link rel="prefetch" href="/assets/js/26.8905d6a0.js"><link rel="prefetch" href="/assets/js/27.b199a955.js"><link rel="prefetch" href="/assets/js/28.524af0cf.js"><link rel="prefetch" href="/assets/js/29.b772949f.js"><link rel="prefetch" href="/assets/js/3.6b94323a.js"><link rel="prefetch" href="/assets/js/30.f5bcac64.js"><link rel="prefetch" href="/assets/js/31.c55e03aa.js"><link rel="prefetch" href="/assets/js/32.e575600a.js"><link rel="prefetch" href="/assets/js/33.3fff5656.js"><link rel="prefetch" href="/assets/js/34.82598567.js"><link rel="prefetch" href="/assets/js/35.8e1290ba.js"><link rel="prefetch" href="/assets/js/36.6dbb9d8c.js"><link rel="prefetch" href="/assets/js/37.d27fdc88.js"><link rel="prefetch" href="/assets/js/38.f8fc7b20.js"><link rel="prefetch" href="/assets/js/39.bf967d40.js"><link rel="prefetch" href="/assets/js/4.706a5607.js"><link rel="prefetch" href="/assets/js/40.e1864fd6.js"><link rel="prefetch" href="/assets/js/41.61bd3b64.js"><link rel="prefetch" href="/assets/js/42.34d8d61d.js"><link rel="prefetch" href="/assets/js/43.1aee493f.js"><link rel="prefetch" href="/assets/js/44.22177e9b.js"><link rel="prefetch" href="/assets/js/45.5c743d2f.js"><link rel="prefetch" href="/assets/js/46.4feffac9.js"><link rel="prefetch" href="/assets/js/47.367f9103.js"><link rel="prefetch" href="/assets/js/48.0c246d45.js"><link rel="prefetch" href="/assets/js/49.ee354be9.js"><link rel="prefetch" href="/assets/js/5.7d9779f7.js"><link rel="prefetch" href="/assets/js/50.bd81c7f0.js"><link rel="prefetch" href="/assets/js/51.a5f432dd.js"><link rel="prefetch" href="/assets/js/52.537aded4.js"><link rel="prefetch" href="/assets/js/53.84814584.js"><link rel="prefetch" href="/assets/js/54.5f780e97.js"><link rel="prefetch" href="/assets/js/55.9d44c91d.js"><link rel="prefetch" href="/assets/js/56.fc164b43.js"><link rel="prefetch" href="/assets/js/57.959b2d44.js"><link rel="prefetch" href="/assets/js/58.bd5c38e0.js"><link rel="prefetch" href="/assets/js/59.3eaece52.js"><link rel="prefetch" href="/assets/js/6.49a49457.js"><link rel="prefetch" href="/assets/js/60.4b8cb735.js"><link rel="prefetch" href="/assets/js/61.b54b9195.js"><link rel="prefetch" href="/assets/js/62.0116614c.js"><link rel="prefetch" href="/assets/js/63.85b1247d.js"><link rel="prefetch" href="/assets/js/64.8f1be6b5.js"><link rel="prefetch" href="/assets/js/65.6a241647.js"><link rel="prefetch" href="/assets/js/66.08c8bd13.js"><link rel="prefetch" href="/assets/js/67.002e0071.js"><link rel="prefetch" href="/assets/js/68.6c6a7c94.js"><link rel="prefetch" href="/assets/js/69.64d90e5d.js"><link rel="prefetch" href="/assets/js/7.469d3b64.js"><link rel="prefetch" href="/assets/js/70.b2c287c9.js"><link rel="prefetch" href="/assets/js/71.b7ad1135.js"><link rel="prefetch" href="/assets/js/72.7391b5c2.js"><link rel="prefetch" href="/assets/js/73.c5c77d81.js"><link rel="prefetch" href="/assets/js/74.96f80ffd.js"><link rel="prefetch" href="/assets/js/75.2920c7b7.js"><link rel="prefetch" href="/assets/js/76.a90bd3c9.js"><link rel="prefetch" href="/assets/js/77.3a0eeccd.js"><link rel="prefetch" href="/assets/js/78.6791678c.js"><link rel="prefetch" href="/assets/js/79.8b0c78e4.js"><link rel="prefetch" href="/assets/js/8.b36167bf.js"><link rel="prefetch" href="/assets/js/80.2641b89d.js"><link rel="prefetch" href="/assets/js/81.03d1925e.js"><link rel="prefetch" href="/assets/js/82.71061708.js"><link rel="prefetch" href="/assets/js/83.df220a8f.js"><link rel="prefetch" href="/assets/js/84.99fbef8f.js"><link rel="prefetch" href="/assets/js/85.dee8bcae.js"><link rel="prefetch" href="/assets/js/86.5200e4ce.js"><link rel="prefetch" href="/assets/js/87.96df0d82.js"><link rel="prefetch" href="/assets/js/88.e9171a32.js"><link rel="prefetch" href="/assets/js/89.53987bbc.js"><link rel="prefetch" href="/assets/js/9.5bed6ebe.js"><link rel="prefetch" href="/assets/js/90.8da0ff06.js"><link rel="prefetch" href="/assets/js/91.4bcce2cd.js"><link rel="prefetch" href="/assets/js/92.aca18707.js"><link rel="prefetch" href="/assets/js/93.93fdf568.js"><link rel="prefetch" href="/assets/js/94.e893b256.js"><link rel="prefetch" href="/assets/js/95.cb1d62b6.js"><link rel="prefetch" href="/assets/js/96.5529545c.js"><link rel="prefetch" href="/assets/js/97.d01eda68.js"><link rel="prefetch" href="/assets/js/98.384bebd6.js"><link rel="prefetch" href="/assets/js/99.fa349b8f.js"><link rel="prefetch" href="/assets/js/vendors~docsearch.aa72e838.js">
<link rel="stylesheet" href="/assets/css/styles.0ff943f0.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container vuepress-theme-fast"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><a href="/zh/" class="home-link router-link-active"><img src="/logo@2x.svg" alt="WEEX" class="logo"></a><span class="version"><a href="/download/download.html" class="version-bg"><img src="/assets/img/version-bg.ab65ded9.svg" alt="v0.28"><span class="version-no">v0.28</span></a></span><div class="links"><form id="search-form" class="algolia-search-wrapper search-box"><input id="algolia-search-input" class="search-query"></form><nav class="nav-links can-hide"><div class="nav-item"><a href="/zh/guide/" class="nav-link">指南</a></div><div class="nav-item"><a href="/zh/docs/" class="nav-link">文档</a></div><div class="nav-item"><a href="/zh/tools/" class="nav-link">第三方工具</a></div><div class="nav-item"><a href="/zh/download/" class="nav-link">下载</a></div><div class="nav-item"><a href="/zh/community/" class="nav-link">社区</a></div><div class="nav-item"><a href="/zh/blog/" class="nav-link router-link-active">博客</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title">选择语言</span><span class="arrow right"></span></a><ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----><a href="/" class="nav-link">English</a></li><li class="dropdown-item"><!----><a href="/zh/blog/weex-auto-test-locating.html" class="nav-link router-link-exact-active router-link-active">简体中文</a></li></ul></div></div></nav><a href="https://github.com/apache/incubator-weex" target="_blank" rel="noopener noreferrer" class="repo-link"><img src="/assets/img/github.7cb484a9.svg" alt="github" class="github-icon"></a></div></header><div class="sidebar-mask"></div><div class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/zh/guide/" class="nav-link">指南</a></div><div class="nav-item"><a href="/zh/docs/" class="nav-link">文档</a></div><div class="nav-item"><a href="/zh/tools/" class="nav-link">第三方工具</a></div><div class="nav-item"><a href="/zh/download/" class="nav-link">下载</a></div><div class="nav-item"><a href="/zh/community/" class="nav-link">社区</a></div><div class="nav-item"><a href="/zh/blog/" class="nav-link router-link-active">博客</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title">选择语言</span><span class="arrow right"></span></a><ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----><a href="/" class="nav-link">English</a></li><li class="dropdown-item"><!----><a href="/zh/blog/weex-auto-test-locating.html" class="nav-link router-link-exact-active router-link-active">简体中文</a></li></ul></div></div></nav><ul class="sidebar-links"><li><a href="/zh/blog/write-a-blog.html" class="sidebar-link">写一篇博客</a></li><li><a href="/zh/blog/weex-auto-test-locating.html" class="active sidebar-link">Weex自动化测试元素定位方案</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/zh/blog/weex-auto-test-locating.html#背景介绍" class="sidebar-link">背景介绍</a></li><li class="sidebar-sub-header"><a href="/zh/blog/weex-auto-test-locating.html#解决方案" class="sidebar-link">解决方案</a></li></ul></li><li><a href="/zh/blog/ios-weexcore.html" class="sidebar-link">iOS WeexSDK 接入 WeexCore</a></li><li><a href="/zh/blog/weexcore-multiprocess-evolution.html" class="sidebar-link">WeexCore 多进程多线程架构演进</a></li><li><a href="/zh/blog/interaction-optimization.html" class="sidebar-link">可交互时间的探索和首屏时间的改进之路</a></li><li><a href="/zh/blog/what_is_the_most_important_assest_to_an_open_souce_project.html" class="sidebar-link">什么是一个开源项目最重要的资产?</a></li><li><a href="/zh/blog/weex-third-party-extensions.html" class="sidebar-link">Weex 三方插件</a></li></ul></div><div class="page"><div class="content"><h2 id="背景介绍"><a href="#背景介绍" class="header-anchor">#</a> 背景介绍</h2><p>在WeexSDK的日常测试和自动化沉淀过程中,作为SDK的测试同学会遇到一下的问题:</p><ol><li>手淘Weex业务众多,并且业务逻辑复杂,人工回归成本高、效率低,并且在手工全覆盖的情况下,因为对业务逻辑的不了解,仍然会有“漏网”的bug。</li><li>对于Weex底层组件的自动化测试中,元素定位是一个比较麻烦的问题。由于Weex特殊的渲染逻辑,不会为每个元素分配一个唯一的id进行区分,在自动化脚本编写过程中,定位元素的成本和稳定性受到考验。</li><li>现有的测试框架,都无法彻底磨平Android、iOS两大平台的差异。作为一个跨平台的开发框架,配套的自动化测试,也能够从底层磨平两个平台的差异,做到一套代码,两端执行。</li></ol><p>针对上述问题,我们在手淘中落地了一个方便快捷的元素定位方案,能够让Weex业务测试同学在前端配合下为指定元素分配一个唯一的ID,方便定位。</p><h2 id="解决方案"><a href="#解决方案" class="header-anchor">#</a> 解决方案</h2><p>在手淘上的元素定位问题,我们参考了@歪木在weex playground中的一个实现方案,为Weex页面提供了一个新的test-id属性,可以方便UI自动化脚本唯一性的快速定位指定元素。具体方案和使用方法如下:</p><h3 id="android"><a href="#android" class="header-anchor">#</a> Android</h3><hr><p><strong>实现原理</strong></p><p><img src="/blog/weex-auto-test-locating/1531211875576-24be9339-cb25-41fc-8b4c-26d74aaf1ddd.png" alt="image.png"></p><p>如上图所示,我们首先在weex页面的根部,创建了一个container节点,用于存储当前页面所有添加test-id属性的节点其test-id值与实际节点ID的映射关系;其次,在页面的layout发生变化时,触发收集新的携带test-id节点的信息,并为其分配一个新的ID;最后,我们将该节点的test-id属性和对应的ID写入到container节点中,方便自动化脚本查询指定节点时,能够获取其真实ID的信息;</p><p><strong>主要代码</strong></p><ul><li>由于Android不支持动态的创建节点ID,只能动态的将view与ID绑定,因此我们预先注册了5000个备用的ID,来作为与weex页面view绑定而使用的ID。</li><li>客户端中通过监听页面Layout变化,触发遍历查找testId属性的逻辑。</li></ul><div class="language-java extra-class"><pre class="language-java"><code><span class="token comment">//Weex页面onCreateView回调时触发,监听当前页面Layout变化,触发执行collectIdTask()</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">View</span> <span class="token function">onCreateView</span><span class="token punctuation">(</span><span class="token class-name">WXSDKInstance</span> instance<span class="token punctuation">,</span> <span class="token class-name">View</span> view<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">View</span> wrappedView <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
observer <span class="token operator">=</span> view<span class="token punctuation">.</span><span class="token function">getViewTreeObserver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
mInstance <span class="token operator">=</span> instance<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">WXEnvironment</span><span class="token punctuation">.</span><span class="token function">isApkDebugable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>instance<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">instanceof</span> <span class="token class-name">WXActivity</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
listener <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ViewTreeObserver</span><span class="token punctuation">.</span><span class="token class-name">OnGlobalLayoutListener</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onGlobalLayout</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>layoutChangeSignal <span class="token operator">==</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token punctuation">{</span>
layoutChangeSignal <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token keyword">new</span> <span class="token function">collectIdTask</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
observer<span class="token punctuation">.</span><span class="token function">addOnGlobalLayoutListener</span><span class="token punctuation">(</span>listener<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>mAnalyzerDelegate <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
wrappedView <span class="token operator">=</span> mAnalyzerDelegate<span class="token punctuation">.</span><span class="token function">onWeexViewCreated</span><span class="token punctuation">(</span>instance<span class="token punctuation">,</span> view<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>wrappedView <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> view<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> wrappedView<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><ul><li>对于一个携带testId属性的节点,为其分配一个nativeId。将testId属性值与nativeId的映射关系写到页面的根节点处。将nativeId动态的赋值到当前节点中。</li></ul><div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">collectId</span><span class="token punctuation">(</span><span class="token class-name">WXComponent</span> comp<span class="token punctuation">,</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> map<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>comp <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">String</span> id<span class="token punctuation">;</span>
<span class="token class-name">View</span> view <span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>id <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> comp<span class="token punctuation">.</span><span class="token function">getAttrs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">&quot;testId&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>view <span class="token operator">=</span> comp<span class="token punctuation">.</span><span class="token function">getHostView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span>
<span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>map<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Pair</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> pair <span class="token operator">=</span> <span class="token class-name">Utility</span><span class="token punctuation">.</span><span class="token function">nextID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
view<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span>pair<span class="token punctuation">.</span>second<span class="token punctuation">)</span><span class="token punctuation">;</span>
map<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> pair<span class="token punctuation">.</span>first<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>comp <span class="token keyword">instanceof</span> <span class="token class-name">WXVContainer</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">WXVContainer</span> container <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">WXVContainer</span><span class="token punctuation">)</span> comp<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token function">getChildCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">collectId</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span><span class="token function">getChild</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">,</span> map<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">collectIDMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>mInstance<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">instanceof</span> <span class="token class-name">WXActivity</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">WXActivity</span> appCompatActivity <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">WXActivity</span><span class="token punctuation">)</span> mInstance<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">View</span> container <span class="token operator">=</span> appCompatActivity<span class="token punctuation">.</span><span class="token function">findViewById</span><span class="token punctuation">(</span><span class="token class-name">R</span><span class="token punctuation">.</span>id<span class="token punctuation">.</span>container_test_id<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">collectId</span><span class="token punctuation">(</span>mInstance<span class="token punctuation">.</span><span class="token function">getRootComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> mIDMap<span class="token punctuation">)</span><span class="token punctuation">;</span>
container<span class="token punctuation">.</span><span class="token function">setContentDescription</span><span class="token punctuation">(</span>JSON<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>mIDMap<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="ios"><a href="#ios" class="header-anchor">#</a> iOS</h3><p>相对于android,weex实现iOS的ById方式就简单多了。做过iOS自动化的同学应该听说过 iOS Accessibility,苹果为障碍人群提供的友好交互功能;iOS UI自动化正好可以与accessibility结合起来进行元素定位,参见:<a href="https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/testing_with_xcode/chapters/09-ui_testing.html" target="_blank" rel="noopener noreferrer">User Interface Testing<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a><a href="https://developer.apple.com/documentation/uikit/uiaccessibilityidentification" target="_blank" rel="noopener noreferrer">accessibilityidentifer<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 是Accessibility的一种方式,用来唯一地标识一个元素使用UI自动化脚本编写的接口。</p><div class="language- extra-class"><pre class="language-text"><code>An identifier can be used to uniquely identify an element in the scripts you write using the UI Automation interfaces.
Using an identifier allows you to avoid inappropriately setting or accessing an element’s accessibility label.
</code></pre></div><p>所以我们只需要在创建view的同时,将test-id作为identifier设置给对应的节点,UI自动化测试时就可以通过ById的方式获得对应的节点了。</p><p>此处代码已经在weexsdk中实现,不需要业务方做任何额外实现。
代码如下:</p><div class="language- extra-class"><pre class="language-text"><code>// 前端的test-id传输到native端会默认转化成testId
if (attributes[@&quot;testId&quot;]) {
[self.view setAccessibilityIdentifier:[WXConvert NSString:attributes[@&quot;testId&quot;]]];
}
</code></pre></div><hr><h3 id="前端实践案例"><a href="#前端实践案例" class="header-anchor">#</a> 前端实践案例</h3><p>下面给出Weex最常见的Vue页面中的使用demo</p><p>对于Vue来说,由于在其内部,会将“XXX-XXX”格式的属性转为驼峰形式命名方式。因此,为了遵从http的命名方式,我们建议在节点属性命名时,使用“test-id”作为元素定位的属性。</p><div class="language- extra-class"><pre class="language-text"><code>&lt;template&gt;
&lt;div style=&quot;align-items:center&quot;&gt;
&lt;text test-id='text' class=&quot;title&quot;&gt;Weex 官网&lt;/text&gt;
&lt;div class=&quot;wrapper&quot;&gt;
&lt;web class=&quot;webview&quot; src=&quot;http://weex-project.io/&quot;&gt;&lt;/web&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;style scoped&gt;
.title {
font-size: 60px;
margin-top: 40px;
margin-bottom: 20px;
color: #1B90F7;
}
.wrapper {
width: 704px;
height: 884px;
border-width: 2px;
border-style: solid;
border-color: #1B90F7;
}
.webview {
width: 700px;
height: 880px;
}
&lt;/style&gt;
</code></pre></div><h3 id="测试脚本"><a href="#测试脚本" class="header-anchor">#</a> 测试脚本</h3><p>由于iOS下,只需要获取“testID”属性即可,此处我们不在赘述在iOS下定位带元素的方法。下面,我们将给出Android下查找test-id的测试代码。而业务方在实际使用过程当中,可以在自己的自动化框架中,封装统一的FindByTestID方法,来达到一套代码双端执行的效果。后续,我们也会对外推出一个基于Appium的测试框架,提供一个功能较为丰富的weex自动化执行框架给外部开发者。</p><p><strong>原理示意图</strong><img src="/blog/weex-auto-test-locating/1531211945217-fe2a8501-dfd8-4372-a3e5-b5007e5bced2.png" alt="image.png"></p><p>针对本方案,我们基于Appium测试框架,实现了对应查找元素的方法。代码逻辑如下:</p><div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">WebElement</span> <span class="token function">waitForElementByTestID</span><span class="token punctuation">(</span><span class="token class-name">String</span> testId<span class="token punctuation">,</span> <span class="token keyword">int</span> waitTime<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> startTime <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">)</span> <span class="token operator">&lt;</span> waitTime<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">WebElement</span> container <span class="token operator">=</span> <span class="token function">waitForVisible</span><span class="token punctuation">(</span><span class="token class-name">By</span><span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token string">&quot;com.taobao.taobao:id/container_test_id&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>container <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">JSONObject</span> idMap <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">JSONObject</span><span class="token punctuation">)</span> JSON<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;name&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>idMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>testId<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">continue</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token class-name">WebElement</span> element <span class="token operator">=</span> <span class="token function">waitForVisible</span><span class="token punctuation">(</span><span class="token class-name">By</span><span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token string">&quot;com.taobao.taobao:id/&quot;</span> <span class="token operator">+</span> idMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>testId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">3000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>element <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
logger<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">&quot;native id found!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> element<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">WebElement</span> <span class="token function">waitForVisible</span><span class="token punctuation">(</span><span class="token class-name">By</span> by<span class="token punctuation">,</span> <span class="token keyword">int</span> waitTime<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">WebElement</span> el <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token class-name">WebDriverWait</span> wait <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WebDriverWait</span><span class="token punctuation">(</span>driver<span class="token punctuation">,</span> waitTime<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> attempt <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> attempt <span class="token operator">&lt;</span> waitTime<span class="token punctuation">;</span> attempt<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
el <span class="token operator">=</span> <span class="token function">getDriver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">findElement</span><span class="token punctuation">(</span>by<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">getDriver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">manage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">timeouts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">implicitlyWait</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span>SECONDS<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
wait<span class="token punctuation">.</span><span class="token function">until</span><span class="token punctuation">(</span><span class="token class-name">ExpectedConditions</span><span class="token punctuation">.</span><span class="token function">visibilityOfElementLocated</span><span class="token punctuation">(</span>by<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> el<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div></div><div class="page-nav"><p class="inner"><span class="prev">
<a href="/zh/blog/write-a-blog.html" class="prev">
写一篇博客
</a></span><span class="next"><a href="/zh/blog/ios-weexcore.html">
iOS WeexSDK 接入 WeexCore
</a>
</span></p></div><div class="page-edit"><div class="last-updated"><span class="prefix">上次更新: </span><span class="time">2020/12/10</span></div><div class="edit-link"><a href="https://github.com/apache/incubator-weex-site/edit/master/docs/zh/blog/weex-auto-test-locating.md" target="_blank" rel="noopener noreferrer">编辑此页</a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><a href="https://github.com/apache/incubator-weex-site/issues/new?body=https%3A%2F%2Fweex.io%2F" target="_blank" rel="noopener noreferrer" class="issueText">提交建议</a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></div><div class="score"><span class="choice"><img src="https://img.alicdn.com/tfs/TB1h7TSqpYqK1RjSZLeXXbXppXa-20-18.svg" class="score-icon">文档写得很棒</span><span class="choice"><img src="https://img.alicdn.com/tfs/TB1h7TSqpYqK1RjSZLeXXbXppXa-20-18.svg" class="score-icon bad">文档写得很差</span></div></div><div class="license-wrap" style="display:none;"><footer class="footer-container" data-v-0ad13d84><div class="footer-body" data-v-0ad13d84><img src="/logo@2x.svg" class="logo" data-v-0ad13d84><img src="//img.alicdn.com/tfs/TB11BRiIW6qK1RjSZFmXXX0PFXa-365-365.png" class="apache" data-v-0ad13d84><div class="cols-container" data-v-0ad13d84><div class="col col-12" data-v-0ad13d84><h3 data-v-0ad13d84>Disclaimer</h3><p data-v-0ad13d84>Apache Weex is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the
Incubator. Incubation is required of all newly accepted projects until a further review indicates that the
infrastructure, communications, and decision making process have stabilized in a manner consistent with
other successful ASF projects. While incubation status is not necessarily a reflection of the completeness
or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.</p></div><div class="col col-4" data-v-0ad13d84><dl data-v-0ad13d84><dt data-v-0ad13d84>ASF</dt><dd data-v-0ad13d84><a href="http://www.apache.org" target="_self" data-v-0ad13d84>Foundation</a></dd><dd data-v-0ad13d84><a href="http://www.apache.org/licenses/" target="_self" data-v-0ad13d84>License</a></dd><dd data-v-0ad13d84><a href="http://www.apache.org/events/current-event" target="_self" data-v-0ad13d84>Events</a></dd><dd data-v-0ad13d84><a href="http://www.apache.org/foundation/sponsorship.html" target="_self" data-v-0ad13d84>Sponsorship</a></dd><dd data-v-0ad13d84><a href="http://www.apache.org/foundation/thanks.html" target="_self" data-v-0ad13d84>Thanks</a></dd></dl></div><div class="col col-4" data-v-0ad13d84><dl data-v-0ad13d84><dt data-v-0ad13d84>Documentation</dt><dd data-v-0ad13d84><a href="/guide/develop/create-a-new-app.html" target="_self" data-v-0ad13d84>Quick start</a></dd><dd data-v-0ad13d84><a href="/guide/develop/setup-develop-environment.html" target="_self" data-v-0ad13d84>Developer guide</a></dd></dl></div><div class="col col-4" data-v-0ad13d84><dl data-v-0ad13d84><dt data-v-0ad13d84>Resources</dt><dd data-v-0ad13d84><a href="/blog/write-a-blog.html" target="_self" data-v-0ad13d84>Blog</a></dd><dd data-v-0ad13d84><a href="/community/" target="_self" data-v-0ad13d84>Community</a></dd><dd data-v-0ad13d84><a href="/guide/contribute/thanks.html" target="_self" data-v-0ad13d84>Thanks by Weex</a></dd><dd data-v-0ad13d84><a href="https://www.apache.org/security/" target="_self" data-v-0ad13d84>Security</a></dd></dl></div></div><div class="copyright" data-v-0ad13d84><span data-v-0ad13d84>Copyright © 2018-2019 The Apache Software Foundation. Apache and the Apache feather
logo are trademarks of The Apache Software Foundation.</span></div></div></footer></div></div><!----></div></div>
<script src="/assets/js/app.0ff943f0.js" defer></script><script src="/assets/js/115.d7e38c3b.js" defer></script>
</body>
</html>