原文: http://www.smashingmagazine.com/2014/10/21/providing-a-native-experience-with-web-technologies/
翻译: 叮当当咚当当小胖妞呀 杀手爱elva Ivan_z3 肖弦
根据最近的一篇 报告显示,HTML是移动应用开发人员使用最多的语言,开发人员对于选择哪种网页技术考虑的最主要因素,是代码的跨平台便携性和开发的低成本性。我们常常听说,hybrid app使用起来非常慢,而且设计也很糟糕,让我们看看是否有可能又有原生应用的形,又有我们习惯使用的感。
这篇文章会提供很多关于如何构建良好的hybrid移动应用的线索、代码片段和经验。我将会大致介绍一下hybrid移动应用的开发,包括它的优点和缺点。然后,我会分享一下过去两年我在开发Hojoki和CatchApp时积累的经验,这两个项目都运行在主流的移动平台,并且是由HTML、CSS和Javascript建成的。最后,我们会介绍一下打包代码到原生app的一些比较好的工具。
移动app可以大致被分为三种,native、hybrid和web app。如果使用native app,你可以使用设备和操作系统的所有能力,同时,平台的性能负荷最小。然而,构建web app可以让你的代码跨平台,使得开发时间和成本大大减少。而hybrid app把这两者的优点都结合起来,使用一套共同代码,在许多不同的平台上部署类似原生的app。
有两种构建hybrid app的方法:
这两种方法都被广泛使用,存在即合理, 不过今天我们只关注WebView app,因为WebView app可以让开发人员平衡他们现有的网页技术。我们来看一下hybrid app相对于native app和web app的各种优点和缺点。
这些缺点比较显著,不能忽略,它们告诉我们,并不是所有的app都适合混合模式,你需要小心的预计你的目标用户、他们对平台的选择和对app的需求。对于许多app来说,好处都是大于坏处的,比如内容驱动的app。
Hojoki和CatchApp都是内容驱动的app,所以我们一开始觉得它们非常适合混合模式的开发方式。我们之前提到的好处中的前三点对于我们构建Hojoki的移动app帮助很大,不过也仅仅是4周的时间而已。显而易见,Hojoki的第一个版本缺失了很多重要的东西,接下来的时间里,我们都把精力扑在提升性能、对每一个平台制作自定义的UI和利用不同设备的高级特性上。那个时候积累的那些经验对于让app形似并神似native app很重要,下面我会尽可能多的分享一下我的经验。
那么, 怎么能让你的app形似并神似一个原生的app呢?对于一个移动网页开发人员来说,能够使用设备和操作系统的能力,能够打包他们的app,这些都听上去很棒。然后,如果要用户相信这是一个native app,那么它就必须长得像并且表现的像。如何完成这一点对于混合模式移动开发人员来说仍然是最大的挑战之一。
虽然我们只写一套基础代码,但这并不意味着多种不同平台上的感官都要完全一样,你们用户根本不在乎什么潜在的跨平台技术,他们只想要app根据他们的期望来展现,他们想要“宾至如归”。你的第一步应该是为每一个平台做设计概览:
虽然这些概览并不能完美适应全部的app,但是它们仍然提供了一套非常全面和标准的界面和体验,每一种平台的用户都会希望得到这样的体验。
如果你一个人实施这些组件、样式和动画,这是个很大的挑战,现在有各种各样的UI框架来帮助你,从商业( Kendo UI)的到开放( lonic)的,从共同UI( JQuery Mobile和 Onsen UI)到许多有平台针对性的UI( Sencha Touch和 ChocolateChip-UI)。有些能够很好的提供精确到像素的布局,有些则相对粗糙,这些各式各样的框架能够很方便的让使用者定义一个web app。然而,就我的观念而言,框架最主要的缺点关乎性能,因为大多数UI框架都尽量“海纳百川”,要根据自己的情况在设备上试试demo后再决定是否要使用。
在制作Hojoki的时候,我们尝试自己用CSS3和极少的Javascript来创建所有的组件,这样做的好处是能够帮助我们控制性能,减少负荷。当然,我们也会使用一些别人使用过的较小的库来解决一下复杂的任务。
自定义UI组件也有很多很好的使用例子,你需要根据你的目标用户来决定使用平台的UI还是自定义UI,如果你想要单干,你需要对UX设计有很深的理解,因为之前的那些概览都是专家们为了迎合他们平台用户的需求而制作的。
不管你是决定坚持使用平台的UI概览还是自己做自定义的组件,你都必须知道,有一些特定的设计样式是用户每天使用并热爱的。通常我们如何把一个app介绍给用户呢?通过幻灯片讲演或者教学覆盖。用户如何导航?如果标签栏或者 侧边栏。用户如何快速加载或者刷新数据?下拉刷新。(在接下来的文章中会讲到类似原生的滚动)
在UI中,标题栏是一个很重要的部分,包括它的标题、导航元素、尤其是前进和后退按钮。对于我来说,许多流行框架在提供HTML和CSS解决方案方面,相比一些原生的app是失败的,而为每个平台用最小的DOM和最少行的css代码来仿照这个UI部分其实相当的简单.
html
Details
在JSFiddle中查看“ IOS、Android和Windows Phone中看起来原生的标题栏”的完整代码,下面是我的成果:
用html5和css做成的看起来原生的标题栏
在不同的平台上使用相同的DOM更为便利,因为代码整洁而且易于维护,我发现这样做对于许多IOS和Android上的UI组件都适用(包括标题栏、标签栏、定制的导航菜单、设置页面、浮层,还有很多其他的东西)。然而,想要更多的支持Windows Phone变得更加困难,因为它带来了许多非常不一样的设计模块。
现如今,高分辨率的智能手机和平板构成了巨大的移动设备市场,在 ios设备中占有率超过80%,在 android设备中占有率超过70%。为了让你设备上的图片展现得更清晰,你通常不得不将其尺寸放大到超过它原本大小的两倍,因此现在响应式网站设计中,如何针对所有不同的分辨率提供适合尺寸的图片,成为了现在热议的话题之一。现在有非常多的途径解决,每一种的优点和缺点都与带宽、代码易维护性和浏览器的兼容性有关,现在让我们来快速的回顾一下当下最流行的方法,顺序不分先后:
一直以来,针对响应式图片都没有一个完美的方法,这主要还是取决于图片的类型和它们在app上的展现使用方式。如果是静态图片(比如logo和教程图片),我尽量使用SVG,它们能不费吹灰之力的完美缩放,并且 只要你是Android 3+就能获得很好的浏览器支持。
当你不能选择SVG的时候, html5的picture元素和srcset属性一定会成为日后前端开发人员的首选。当下,它们最大的不足就是在浏览器上的支持太局限,因此他们需要一些插件.
同时, css背景图片和media queries是比较可靠的解决方案:
css
/* Normal-resolution CSS */
.logo {
width: 120px;
background: url(logo.png) no-repeat 0 0;
}
/* HD and Retina CSS */
@media
only screen and (-webkit-min-device-pixel-ratio: 1.25),
only screen and ( min--moz-device-pixel-ratio: 1.25),
only screen and ( -o-min-device-pixel-ratio: 1.25/1),
only screen and ( min-device-pixel-ratio: 1.25),
only screen and ( min-resolution: 200dpi),
only screen and ( min-resolution: 1.25dppx) {
.logo {
background: url([email protected]) no-repeat 0 0;
background-size: 120px; /* Equal to normal logo width */
}
}
但是,你的app也许已经包含了许多内容(比如新闻文章),要调整所有的图片标签或者用css替代会让我们筋疲力竭,在这种情况下,服务端解决方案就会是最好的选择。
从去年开始,越来越多的android系统已经离XXHDPI(超高分辨率)屏幕又进了一步。不论上面提到的哪种方案更适合你的需要,你要记住的是你需要用到三倍于原图大小的图片来支持android的最新的设备。
使用系统字体是一种让用户体感到宾至如归的一种简单但是重要的方法。
ios、 android和 windows的原生字体
主流平台上,我比较推荐这些字体样式:
/* iOS */
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
/* Android */
font-family: 'RobotoRegular', 'Droid Sans', sans-serif;
/* Windows Phone */
font-family: 'Segoe UI', Segoe, Tahoma, Geneva, sans-serif;
此外,ios7提供了一些有趣的预处理,这些预处理可以自动的设置正确的字体、文字大小和行高,在普通文本中应用 font:-apple-system-body
,在标题中使用 font:-apple-system-headline
,这样不仅简化了文字的声明,而且还提升了 动态类型(这是Apple系统范围的字号设置)的可访问性,你可以在 Thomas Fuchs的文章中了解到更多关于ios7的字体预处理。
图像学在所有主流移动平台的用户体验上是一个重要的部分。相比字体,你一定更愿意使用用户已知的icon,回顾一下我之前说过的高分辨率屏幕,要确保你的icon的大小是可调节的,将它们作为字体通过css的 @font-face
来实现,浏览器会有很好的兼容性支持,你甚至可以通过css改变icon的样式(比如颜色、阴影和透明度)。以下是我的推荐:
s
在IOS、Android和Windows Phone中看起来是一个搜索图标。同时,还可以了解一些其他比较流行的方案,比如 IcoMoon和 Fontastic。在 Windows Phone上,你还可以 脱离Native font-family: 'Segoe UI Symbol'
。
性能经常被认为是hybrid移动app中一个主要的缺陷,尤其当你的app有大量的动画,包含大量的滚动列表并且需要在旧设备上运行的时候,缺点会越发的明显。然而,如果你觉得能够接受只支持一些比较新的平台版本(Android 4+,iOS 7+和Windows Phone 8+)的话,那你应该就会看到满意的效果。最终的问题就在于你在优化DOM和CSS选择器、书写高性能的Javascript、减少渲染时间和最少化重排重绘上花了多少工夫。关于移动网页性能的文章和教程一大把,以下是我最喜欢的一些:
“ 成功PhoneGap App的性能和UX考虑因素”,Andrew Trice
“ 移动:网页性能” (幻灯片),Estelle Weyl
“ 书写快速、内存高效的Javascript,” Addy Osmani, Smashing Magazine
“ 浏览器重排最少化,” Lindsey Simon, Google Developers
“ 如何让你的网站在移动设备上运行更快,” Johan Johansson, Smashing Magazine
此外,随着每天都有新的设备推出,移动硬件和渲染引擎都在以一个非常迅猛的速度提升,开发者能够做到使iPhone5系列、Android手机与Nexus4和5的纯原生App的性能上基本一致。
构建高效的app是一回事而,让app感觉上运行很快又是另一回事儿。无论你的app是否需要一些时间来完成某项任务(比如一些复杂的计算或者客户端和服务器端的交流),实时反馈对于提供流畅和响应式体验至关重要。一个比较常用的方法是,在用户还不需要某些功能的时候推迟加载,对用户接下来可能进行的操作作预估和预加载。Instagram有一个著名的例子,当用户忙于添加标签和分享的时候, 在后台上传图片。感知速度和真正的速度是不一样的,让我们合理运用它。这里有一些非常简单的例子:
触屏设备中的一个普通Javascript点击事件,从点击的最开始到得到响应会有轻微的延迟(大约300毫秒),浏览器的这种行为是在判断用户是单击还是双击,如果你不需要“双击以放大”特性,你可以安全的消除这300毫秒从而换取更多响应操作,我最喜欢的解决方案是 FastClick库,你可以把它用在除了IE的所有浏览器上:
js
if ('ontouchstart' in window) {
window.addEventListener('load', function() {
FastClick.attach(document.body);
}, false);
}
IE10以上比较容易解决,你只需要添加一些css代码:
css
html {
-ms-touch-action: manipulation; /* IE 10 */
touch-action: manipulation; /* IE 11+ */
}
只要用户点击一些可操作的元素(例如按钮或者链接),app检测到以后应该马上给他们一些回应。就像在台式机上表现不错的css的伪类 :hover
,在移动端你需要换成 :active
或者一些javascript解决方案。我曾经在JSFiddle上比较过三种 点击状态的方案,你可以根据你的实际情况使用。
还有,记得在调整移动端点击状态的时候清楚默认点击高亮的样式,此外我建议禁用用户在一些活动的元素上选择,因为如果用户不小心点击按钮的时间过长,出现的选择菜单会很烦人。
iOS and Android:
css
button {
outline: 0;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
Windows Phone 8+:
html
你的app总是需要一些时间来完成动作,即使只有一秒,所以要考虑添加加载提示,否则用户就可能认为有时候app卡住了,或者在不应该点击的时候乱点,甚至他们可能会乱砸东西并且归责于你的app。根据我的经验,移动端浏览器运用gif动画不是一个好方法。一旦CPU上有一个加载项,gif卡住了,那么这个GIF对用户的加载提示就完全没有作用了。我更喜欢 Spin.js,因为可以自己配置并且运用简单,当然,还有一些其他的方法: javascript解决方案和 css加载方案。
一些跨平台的工具比如PhoneGap和Trigger.io也提供一些原生的加载状态,对于全屏动画加载的展现很棒。
滚动在许多app中是决定用户体验的最重要因素之一,它让人又爱又恨,因为要实现这一点取决于你应用依赖的滚动细节以及需要手机系统支持。
几乎所有的app都使用了可滚动内容和固定头部和/或底部。通常有两个CSS方法来实现:
body
上启用滚动,在header上增加 position: fixed
;body
上禁用滚动,在内容上增加 overflow: scroll
;body
上禁用滚动,在内容上增加JavaScript默认滚动。虽然第一种方法有一些优点(例如IOS的原生滚动到顶部动作以及简洁的代码结构),我强烈推荐第二种方法: overflow: scroll
。这个方法 渲染问题更少(虽然还是比较多),现代平台上的浏览器支持更好(Android 4+,IOS 5+和Windows Phone 8+),对于低版本浏览器有 方便的小插件。另外,你可以把 overflow: scroll
换成自定义的滚动库(第三种选择),例如 iScroll。虽然这些JavaScript解决方案使得特性更加灵活(例如,带动量效果的滚动位置,事件处理,可定制的效果和滚动条等),但它们通常会影响性能。当你在内容里用了许多DOM节点和/或CSS效果(例如 box-shadow
, text-shadow
, opacity
和 rgba
)时会很危险。
让我们来看一些基本的滚动特性。
触摸友好的动量效果使得用户在大块内容区域的快速滚动显得很直观。通过一些简单的CSS就能在IOS 5+以及Android上一些版本的Chrome中激活。在IOS上,这也会使得内容不溢出顶部和底部边界。
css
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
网页上有许多实现这个效果的方法,例如 Damien Antipa写的一种。这个方法在IOS和Windows Phone中效果和体验很相似,Android最近发布它特有的结构(如下)。我们通过一些JavaScript和CSS keyframes在CatchApp里实现了这个效果。(我还没有总结好放到Github上,所以还在调整!)
IOS中的下拉刷新。 (图片属于: Damien Antipa)
Android中的下拉刷新。 (图片属于: Android Widget Center)
Windows Phone中的下拉刷新。 (图片属于: David Washington)
不幸的是,在 body
上禁用滚动的同时会破坏IOS中允许用户通过点击状态栏快速回到页面顶部的原生特性。我写了一小段可以添加在任何元素上的脚本来使用JavaScript解决 滚动到顶部的问题,即便内容当前处于动量效果中。把它添加到手机端网页头部或通过原生插件添加到状态栏上(例如,PhoneGap)。
许多其他滚动的特性可以通过原生 overflow: scroll
实现,例如关闭特定元素或只是无限滚动。如果需求更加复杂,一定考虑使用JavaScript方法。
用户触摸时,很容易跟目标偏差几个像素,尤其是点击小按钮时(例如IOS顶部条上的按钮)。开发者可以在保证设计的情况下通过在小目标周围开启不可见触摸区域来使用户体验更好。
html
你需要在按钮元素上绑定事件处理器,同时用 div.innerButton
定义样式。在JSFiddle上查看 完整的,含有CSS的例子。
智能手机的精髓就是触摸和手势。在和触摸设备交互时,我们总是滑动,按压,缩放,拖动和长按。所以,为什么不提供相同的方式来让用户控制你的hybird应用呢? QuoJS和 Hammer.js是广为人知的支持所有手势类型的库。如果你想要更多选择,看一下Kevin Liew对” 11个多点触摸和触摸事件JavaScript库“的比较。
用网页技术构建你的应用并不意味着你不能用原生特性。事实上,所有主要的跨平台开发工具提供了提供了内置的对重要功能的接口。其中有许多API包括调用设备数据,文件系统,网络连接,地理位置定位,加速度传感器,提示(包括推送)等等。
通常,你甚至可以通过构建自定义插件来扩展开发工具。在Hojoki,我们加入了许多缺失的特性,包括读取用户对于我们app的推送提示的设置,读取用户时区,检查是否安装第三方APP并启动。让我们来看两个关于用原生插件实现的效果的例子。首先,让我们对IOS 6+里的input启动JavaScript focus()
:
js
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6) {
[YourWebView setKeyboardDisplayRequiresUserAction:NO];
}
下面是在IOS上把给定字符串复制到设备剪贴板里的代码:
[[UIPasteboard generalPasteboard] setString:@"Your copied string"];
网页开发者经常忽视如何处理hybird应用中的糟糕情况(例如,连接超时,错误输入,时间问题等等)。hybird应用从根本上区别于网站,主要因为它没有全局刷新按钮,在一些移动端操作系统里应用很容易在后台运行数周。如果用户死机了,他们唯一的选择是重启应用,这势必要强制退出然后重启。许多人甚至不知道怎样重启,尤其是在Android 2.x上(它深深隐藏在app设置里)和IOS 6及以下版本上(你需要双击home键,长按图标并且关闭它)。
所以,在开发中先不要觉得有刷新按钮就万事大吉而不考虑出错的情况,我们应该做的是遇到问题就立即解决。对于其他所有意外的情况,例如包含客户端-服务端的通信,准备好应对错误情况,给用户提供一个出口。可以简单得显示一个全屏的错误信息-“欧!出了些问题。请检查你的连接并再次尝试”-下面放一个大大的“重新载入”按钮。
开发hybrid移动app就需要用到通常开发(移动)网站一样的工具,开发流程也一样。虽然这么说,我真正喜欢hybrid的地方是你能比较轻松地使用HTML、CSSS和JavaScript来部署移动web app。确保对原生特性实现回退,或在完全不支持该特性的情况下找到优雅的解决方案。大多数移动开发者更喜欢让用户群留在原生app上,甚至可以向使用移动网站的用户宣传这个app。
基于HTML、CSSS和JavaScript的原生WebView打包器
那原生部分怎样呢?移动web app(纯的HTML、CSSS和JavaScript)将加载到一个WebView中。作为一个内部浏览器引擎,WebView会按照设备的默认浏览器渲染网页的方式渲染app(可能会存在细微差别——你遇到的情况可能有所不同)。而且,原生“应用开发平台”用来暴露设备和操作系统的特性,而JavaScript能通过API调用到这些特性。这个API通常包含有调用特性的接口,比如设备摄像头、通讯录、地理位置、文件系统和原生事件(比如通过Android的硬件按钮)等特性。
有一些跨平台的开发工具提供了原生应用开发平台,简化了整个打包流程。下面深入研究部分工具。
PhoneGap绝对是一个最流行的跨平台开发工具之一,它的名字本身经常被当作hybrid移动app开发的同义词。
关于它的名字以及与 Apache Cordova的关系存在的 一些误解是可以理解的。后者是顶级Apache项目,曾用名就是PhoneGap。它提供了一套设备API,并通过运行在WebView中的HTML、CSSS和JavaScript调用原生的功能。现在,Adobe PhoneGap是Cordova的一个分支——与Chrome使用Webkit作为其引擎没有什么不同。
两者都是开源和免费的,支持所有主流平台,拥有一个开发各类插件和扩展的活跃社区。
PhoneGap对塑造hybrid贡献巨大,涌现出的很多新的工具提供了 附加功能,使开发流程简单。这些工具带来了很多便利:通过在云端构建app,免去了在本地安装所有不同平台的SDK和工具的工作。每个工具都有不同的关注点、平台支持度和价钱:
Sencha Touch最初是一个针对移动web的UI框架,存在有几年了。过去,开发者使用Sencha构建app需同时使用其他如PhoneGap这样的服务来部署成hybrid app。现在Sencha内置了这种功能,可免费使用。支持的平台有iOS和Android(都需要通过Sencha自有的原生打包工具),BlackBerry、Windows 8等更多(通过PhoneGap Build)。
在Hojoki,我们在两年半前开始用 Trigger.io,因为当时想找一个比PhoneGap轻量级的替代品。虽然它只支持iOS和Android平台,但它提供了一套很不错的原生API、自定义插件和第三方集成(包括Parse消息推送服务、Flurry分析器以及部分Facebook的SDK)。通过Trigger.io的命令行工具,可以将app打包集成到 Grunt的构建过程。如果喜欢自动化,这一点很棒。
它的一个重要特性是 Reload,该特性能使开发者推送HTML、CSSS和JavaScript的更新到运行中的app。与PhoneGap Build的 Hydration不同,Reload专门为开发和生产app设计。这样就使得合法绕过Apple的提交流程去提交bug解决方案和用A/B测试快速迭代就成为可能。
对很多开发者来说,一旦14天的试用期结束,Trigger.io 极高的价格可能就是它最大的缺点。
MoSync似乎是另一种不与PhoneGap有瓜葛的工具,但不太确定当下它的开发活跃度怎样。
显然,用web技术构建移动app会诱使我们在web浏览器上做大部分的测试。在开发非原生特性时还算说得过去,但在发布时一定要避免。提交app之前,要在尽量多的生产商、平台和各种机型各种版本上测试。Android的机型和版本太多,在浏览器渲染、特性支不支持和生产商更改上会千差万别。虽然iOS渲染的差异好很多,但Apple生产的不同尺寸、分辨率和像素密度的设备越来越多。想了解更多请点击查看“ 设备优先级:测试和响应式web设计”。
在2012年,Facebook放弃绝大部分HTML5开发转向原生开发,其中一个主要原因是“ 缺少调试工具和开发者API”。半年后, LinkedIn得出同样的结论,声称HTML5本身准备好了,但基础工具和生态系统还没来得及支持它。从我的角度来说,情况正变得越来越好:Android 4.4+支持WebView的远程调试;各平台的开发工具越来越多:
为web浏览器构建app时,为用户部署修复程序是简单的一步,这意味着测试会失去其重要性。当通过app商店发布app,这就需要重新考虑了。把它想成上世纪90年代的软件开发:你现在就生活在硬发布的世界里。
那么,为什么这很糟糕?首先,提交过程随便就是一两周(寨见,Apple!)。其次,即使修复程序很快发布,也不能保证用户在短时间更新app。以下是我的建议:
上面提到的工具会为每个平台生成一个版本,然后将这些版本提交到相应的商店。从这点,过程和发布一个“普通”的原生app几乎一样。在这方面,有些已讨论过的工具可能有更好的文档。尽管这样,以下是官方指南:
既然开发的hybrid移动app在Apple的App商店和Google Play已经上线两年了,这里我就总结下在本文开头提到的一些优点和缺点。
对于我们这样一个资源有限、没有原生iOS和Android开发经验的创业公司,要在短短的几周内构建一个多平台的app是不可能的。选择hybrid,我们就能复用很多web app的代码,根据用户反馈迭代速度就快。我们已经成功发布了支持桌面Windows 8和微软Surface的原生app,支持Mac OS X的app也使用了基本一样的代码。移植到另一个平台的工作量很大程度上取决于给定浏览器与设备的能力和所需要的原生功能的水平高低。我们需要消息推送、app内置购买、获取用户联系方式,以及其他功能。根据你的需求,很多原生功能会使你很依赖于所选择的原生打包工具。
最后,我们来看看hybrid app是否真的能给出一个原生的感官享受。以下精选了来自app商店的用户评论。积极和消极的评论都有,其中很多消极的评论来自早期版本——各平台UI一样,性能相对较慢。
评论略去
的确,我们正远离特定平台的app开发而面向不断涌现的很多新技术。去年的Google I/O大会上被问到关于web的未来, Larry Page说:
在很长一段时间,我不认为作为开发者的你会考虑是否为这个平台或那个平台或其他类似平台在开发。我认为你应该在更高的层次上工作,你所写的软件能在每个平台运行起来,而且是很容易地运行起来。
在这方面,(移动)web取得了很大的成功。使用这个平台而且仍然能在所有商店分发app是向前迈出的巨大一步。未来会发生什么敬请期待。无论发生什么,使用 世界上1/3人口(其中超过2/3来自欧洲和美国)依赖的技术大概不会是一个坏的选择。