![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/00/00/16_avatar_mid.jpg?v=0)
关于HTML、js加密、混淆、源码保护、代码安全,防止解压直接看源码
更新:HBuilderX下,包括5+app和uni-app的使用方式,另见文章https://ask.dcloud.net.cn/article/36437`
================以下文章是老HBuilder的加密介绍====================
一直有人问HTML加密混淆怎么做,其实这在业内是早已很多人研究过的课题。
假日期间整理一篇文章分享给大家。
我们先理下需求,加密的目的是什么?加密到什么级别?为此我们可以牺牲什么?
我们知道这个世界不存在绝对的安全,加密会被破解、混淆会被反混淆。
技术小白、开发者、黑客,是完全不同的级别,防范不同级别的人策略都不一样。
防范力度越大,投入代价也越大,比如聘请专业的安全公司。
除了投入,我们还需要考虑程序的执行性能和用户体验。
加密的代码在运行时必须解密,混淆后尤其是混淆HTML后,程序的执行性能会下降。
是否真的有必要做这类的源码保护,还需要谨慎取舍。
一般而言,前端的代码,负责的是用户体验,后端的代码,负责更安全的数据处理。
前端不要涉及泄漏太多涉密信息,那么加密的意义不是特别大。
我很少在前端代码里看到值得保护的内容,比如高深的算法,很多代码是没必要牺牲用户体验来保护的。
但有些前端代码涉及最终用户的数据安全,此时还是要努力做数据保护的。
接下来具体分析几种手段。
-
不要在前端放敏感数据
这个听起来是废话,但真的很重要。
有些开发者在手机端明文存用户的密码,这是非常危险的事情。
即使是原生开发,一旦手机被root,也会造成数据泄漏。更何况HTML5开发。
比较好的做法是手机端存token,而不是密码,这里有篇文章专门介绍这块,涉及做登录的开发者推荐仔细看看设计基于HTML5的APP登录功能及安全调用接口的方式(原理篇) -
js、css压缩
压缩不是加密,也不是混淆。但压缩后的js文件,往往也具有混淆的功能。
js、css压缩是很常见的技术,我们经常看到各种框架的文件名是xxx.min.js,xxx.min.css。
使用合适的js、css压缩方案,可以减少文件体积、提高载入速度,最重要的是,它还能加快程序的执行性能。简直是有百利而无一害。
压缩js比较常用的工具是yahoo的YUI混淆,在HBuilder里点菜单工具-插件安装,里面有YUI compress,可以压缩js和css。
如果js、css比较大,发布前压缩下是比较推荐的做法。 -
HTML、js、css混淆
压缩虽然也能混淆,但不是以让别人看不懂为目的,混淆是真正以别人看不懂为目的。
但是这样的混淆就不像压缩那么有百利而无一害了,它会降低程序执行性能。
一些开发者不希望发行包解压后可以直接看到源码,那么此时可以使用混淆方案。
网上搜索HTML混淆,资料和工具都非常多。
原理都是类似的,js代码变成乱七八糟的字符串,然后用eval执行,HTML代码变乱七八糟字符串,用document.write或innerHTML执行,css也可以动态的在document.write里写<style>。
这些工具有免费也有商业的,一般越商业的越难被反混淆。
这个是免费的在线混淆工具 http://www.myobfuscate.com
这个是比较知名的商业工具,http://www.jasob.com
其实大家也可以根据原理自己写混淆算法。
混淆也是一个有年头的成熟技术,比如Google在保护gmail的前端代码时,也是通过混淆来保护的。
不管是压缩还是混淆,使用grunt来做发布是不错的方式,开发后一键调用grunt处理,非常便捷。
HBuilder在原生层面支持js混淆,性能高于前端混淆。详情下面第6点。这篇文章对于前端的代码保护也讲的非常专业,值得大家学习http://div.io/topic/1220
-
防止webkit remote debug,即防止浏览器控制台调试
Android4.4及以上和iOS是支持webkit remote debug的,在HBuilder的教程里也有如何使用chrome调试Android应用,和使用safari调试iOS应用的教程。
在HBuilder开发的App里,manifest.json里下的plus-distribute下有一个debug标签,标记为false后打包(可视化界面里也有配置),这样的包运行在手机上时webview会阻止浏览器的远程调试请求。
如果你想调试,那么把debug改为true后再打包。
当然有些Android rom不是很规范,并不能阻止调试,这属于rom的bug。
另外注意只有打包才能防调试,真机运行是不能阻止调试的。 -
专业加密加固加壳服务
由于Android的特殊性,针对apk出现了加固、加壳产业,这也是业内常见的apk保护方案。
很多应用市场都提供加固服务,比如360手机助手的加固。
还有一批专业公司如爱加密,里面有免费的基础安全保障服务,也有收费的高级安全保障服务。
这里还有一个防止apk解压的小技巧:http://www.52pojie.cn/thread-287242-1-1.html -
HBuilder提供的原生js混淆
在HBuilder或HBuilderX中,官方提供了原生层面的js混淆。
这种混淆的性能比纯前端混淆的性能要更好,反编译的难度也更大。但有些限制和使用注意:- Android4以下的手机不能运行加密后的js。
- 5+App下,iOS若配置wkWebview,则不能运行加密后的js。
具体使用方式是在打包界面,可以选择需要加密的js文件,然后打包即可。如下图:
更新:HBuilderX下,包括5+app和uni-app的使用方式,另见文章https://ask.dcloud.net.cn/article/36437`
================以下文章是老HBuilder的加密介绍====================
一直有人问HTML加密混淆怎么做,其实这在业内是早已很多人研究过的课题。
假日期间整理一篇文章分享给大家。
我们先理下需求,加密的目的是什么?加密到什么级别?为此我们可以牺牲什么?
我们知道这个世界不存在绝对的安全,加密会被破解、混淆会被反混淆。
技术小白、开发者、黑客,是完全不同的级别,防范不同级别的人策略都不一样。
防范力度越大,投入代价也越大,比如聘请专业的安全公司。
除了投入,我们还需要考虑程序的执行性能和用户体验。
加密的代码在运行时必须解密,混淆后尤其是混淆HTML后,程序的执行性能会下降。
是否真的有必要做这类的源码保护,还需要谨慎取舍。
一般而言,前端的代码,负责的是用户体验,后端的代码,负责更安全的数据处理。
前端不要涉及泄漏太多涉密信息,那么加密的意义不是特别大。
我很少在前端代码里看到值得保护的内容,比如高深的算法,很多代码是没必要牺牲用户体验来保护的。
但有些前端代码涉及最终用户的数据安全,此时还是要努力做数据保护的。
接下来具体分析几种手段。
-
不要在前端放敏感数据
这个听起来是废话,但真的很重要。
有些开发者在手机端明文存用户的密码,这是非常危险的事情。
即使是原生开发,一旦手机被root,也会造成数据泄漏。更何况HTML5开发。
比较好的做法是手机端存token,而不是密码,这里有篇文章专门介绍这块,涉及做登录的开发者推荐仔细看看设计基于HTML5的APP登录功能及安全调用接口的方式(原理篇) -
js、css压缩
压缩不是加密,也不是混淆。但压缩后的js文件,往往也具有混淆的功能。
js、css压缩是很常见的技术,我们经常看到各种框架的文件名是xxx.min.js,xxx.min.css。
使用合适的js、css压缩方案,可以减少文件体积、提高载入速度,最重要的是,它还能加快程序的执行性能。简直是有百利而无一害。
压缩js比较常用的工具是yahoo的YUI混淆,在HBuilder里点菜单工具-插件安装,里面有YUI compress,可以压缩js和css。
如果js、css比较大,发布前压缩下是比较推荐的做法。 -
HTML、js、css混淆
压缩虽然也能混淆,但不是以让别人看不懂为目的,混淆是真正以别人看不懂为目的。
但是这样的混淆就不像压缩那么有百利而无一害了,它会降低程序执行性能。
一些开发者不希望发行包解压后可以直接看到源码,那么此时可以使用混淆方案。
网上搜索HTML混淆,资料和工具都非常多。
原理都是类似的,js代码变成乱七八糟的字符串,然后用eval执行,HTML代码变乱七八糟字符串,用document.write或innerHTML执行,css也可以动态的在document.write里写<style>。
这些工具有免费也有商业的,一般越商业的越难被反混淆。
这个是免费的在线混淆工具 http://www.myobfuscate.com
这个是比较知名的商业工具,http://www.jasob.com
其实大家也可以根据原理自己写混淆算法。
混淆也是一个有年头的成熟技术,比如Google在保护gmail的前端代码时,也是通过混淆来保护的。
不管是压缩还是混淆,使用grunt来做发布是不错的方式,开发后一键调用grunt处理,非常便捷。
HBuilder在原生层面支持js混淆,性能高于前端混淆。详情下面第6点。这篇文章对于前端的代码保护也讲的非常专业,值得大家学习http://div.io/topic/1220
-
防止webkit remote debug,即防止浏览器控制台调试
Android4.4及以上和iOS是支持webkit remote debug的,在HBuilder的教程里也有如何使用chrome调试Android应用,和使用safari调试iOS应用的教程。
在HBuilder开发的App里,manifest.json里下的plus-distribute下有一个debug标签,标记为false后打包(可视化界面里也有配置),这样的包运行在手机上时webview会阻止浏览器的远程调试请求。
如果你想调试,那么把debug改为true后再打包。
当然有些Android rom不是很规范,并不能阻止调试,这属于rom的bug。
另外注意只有打包才能防调试,真机运行是不能阻止调试的。 -
专业加密加固加壳服务
由于Android的特殊性,针对apk出现了加固、加壳产业,这也是业内常见的apk保护方案。
很多应用市场都提供加固服务,比如360手机助手的加固。
还有一批专业公司如爱加密,里面有免费的基础安全保障服务,也有收费的高级安全保障服务。
这里还有一个防止apk解压的小技巧:http://www.52pojie.cn/thread-287242-1-1.html -
HBuilder提供的原生js混淆
在HBuilder或HBuilderX中,官方提供了原生层面的js混淆。
这种混淆的性能比纯前端混淆的性能要更好,反编译的难度也更大。但有些限制和使用注意:- Android4以下的手机不能运行加密后的js。
- 5+App下,iOS若配置wkWebview,则不能运行加密后的js。
具体使用方式是在打包界面,可以选择需要加密的js文件,然后打包即可。如下图:
![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/08/77/69_avatar_mid.jpg?v=0)
菜鸟福利-----以有道翻译API为例说明mui ajax的用法详解
第一步:在有道官方网站申请一个API key
举例:
API key:1207861310
keyfrom:abc1243
调用说明:
http://fanyi.youdao.com/openapi.do?keyfrom=<keyfrom>&key=<key>&type=data&doctype=<doctype>&version=1.1&q=要翻译的文本
版本:1.1,请求方式:get,编码方式:utf-8
主要功能:中英互译,同时获得有道翻译结果和有道词典结果(可能没有)
参数说明:
- type - 返回结果的类型,固定为data
- doctype - 返回结果的数据格式,xml或json或jsonp
- version - 版本,当前最新版本为1.1
- q - 要翻译的文本,必须是UTF-8编码,字符长度不能超过200个字符,需要进行urlencode编码
- only - 可选参数,dict表示只获取词典数据,translate表示只获取翻译数据,默认为都获取
注: 词典结果只支持中英互译,翻译结果支持英日韩法俄西到中文的翻译以及中文到英语的翻译
errorCode:
- 0 - 正常
- 20 - 要翻译的文本过长
- 30 - 无法进行有效的翻译
- 40 - 不支持的语言类型
- 50 - 无效的key
- 60 - 无词典结果,仅在获取词典结果生效
注意修改标记的四个地方,只需要修改q的值为你想要的翻译内容即可。
点击下方链接我们可以得到:
http://fanyi.youdao.com/openapi.do?keyfrom=abc1243&key=1207861310&type=data&doctype=json&version=1.1&q=翻译
可是网上多半就停留在此并没有告诉我们怎么在程序里面发出请求然后获取数据,之前找过一些例子,都是服务器端语言调用的,所以我误以为只能通过服务器端语言才能调用,结果一次在群里问了问,一个大神告诉说其实ajax就可以咯,于是之间就去找了找ajax的教程看了看,但是没怎么看懂,一大堆什么XMLHttpRequest 什么的,试了试还是各种理不清,找官方demo改了改,发现mui的ajax还是挺好懂的,格式也比较固定,对于菜鸟的我来说感觉这个才是最好的,不要先来一大堆没用的,废话少说,试试看就知道咯。
第二步:ajax跨域请求的简单实例
先来个最简单的直接点击按钮弹出返回的数据,只要这个成功了,那么改改还是很容易的。
【html部分】:
<button type="button" id="confirm" class="mui-btn mui-btn-royal mui-btn-block">发送请求</button>
【js部分】:
<script src="js/mui.min.js"></script>
<script>
//发送请求按钮的点击事件
document.getElementById("confirm").addEventListener('tap', function() {
var url = "http://fanyi.youdao.com/openapi.do?keyfrom=abc1243&key=1207861310&type=data&doctype=json&version=1.1&q=good";
mui.ajax(url,{
dataType:'json',//服务器返回json格式数据
type:'GET',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
//JSON.stringify()将 JSON对象转为json字符串
var data = JSON.stringify(data);
alert(data);
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
});
</script>
第三步:传递参数的ajax跨域请求
上面URL中把各种请求参数写固定了,不便于我们后期做修改,现在用ajax的data属性。
首先我们增加一个搜索输入框用于输入要翻译的内容:
修改html的代码如下:(样式文件没有引入,样式也没有写出来,主要是为了写清楚思路)
【html部分】
<form name="search" method="get">
<div class="mui-input-row mui-search input-search">
<input type="search" id="search" class="mui-input-speech mui-input-clear" placeholder="请输入内容...">
</div>
<button type="button" id="confirm" class="mui-btn mui-btn-royal mui-btn-block">发送请求</button>
</form>
【js部分】(修改部分的代码)
var search = document.getElementById("search");
//发送请求按钮的点击事件
document.getElementById("confirm").addEventListener('tap', function() {
var url = "http://fanyi.youdao.com/openapi.do";
mui.ajax(url,{
data:{
keyfrom:"abc1243",
key:"1207861310",
type:"data",
doctype:"json",
version:"1.1",
q:search.value
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
//JSON.stringify()将 JSON对象转为json字符串
var data = JSON.stringify(data);
alert(data);
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
});
第四步:ajax跨域请求怎么处理获取的数据
我们刚刚只是把数据alert出来了但是并没有进行任何后期操作,比如把有用信息获取写出来。
我们是把刚刚那个变成了json字符串alert出来的,也就是说是字符串而不是对象,获取键值对必须是对对象进行操作。
那么我们首先使用eval函数把json字符串转化成JavaScript对象:
//将json字符串转化成JavaScript对象
var obj = eval ("(" + response + ")");
然后我们就可以对obj对象进行操作了,json键值对的[] 中括号的使用如下:
JSON就是一串字符串 只不过元素会使用特定的符号标注。
- {} 双括号表示对象
- [] 中括号表示数组
- "" 双引号内是属性或值
- : 冒号表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
所以 {"name": "Michael"} 可以理解为是一个包含name为Michael的对象,而[{"name": "Michael"},{"name": "Jerry"}]就表示包含两个对象的数组。
var LangShen = {"Name":"Langshen","AGE":"28"};
这是一个json对象;{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数上面声明了一个名为“LangShen”的对象,多个属性或函数用,(逗号)隔开,因为是对象的属性,
那么我们访问的时候会有两种方式:
访问方式一:LangShen.Name、LangShen.AGE
访问方式二:LangShen["Name"]、LangShen["AGE"]
就是这么一个小小的方式,会有什么区别呢?
在实际应用中,第一种方式的.Name实际是作为一个对象被调用,而LangShen["Name"]里的name却可以是一个字符串。
有道翻译API获取实例:
我只是写出了基本思路,无非就是把对于内容写在对应的位置。
document.getElementById("translation").innerHTML=obj.translation;
document.getElementById("us-phonetic").innerHTML=obj.basic["us-phonetic"];
document.getElementById("phonetic").innerHTML=obj.basic["phonetic"];
document.getElementById("uk-phonetic").innerHTML=obj.basic["uk-phonetic"];
document.getElementById("explains").innerHTML=obj.basic["explains"];
document.getElementById("query").innerHTML=obj.query;
//遍历读取键值对写入
for(var str in obj.web){
var keyid=document.getElementsByName("webkey")[str].id;
var Valueid=document.getElementsByName("webvalue")[str].id;
document.getElementById(keyid).innerHTML=obj.web[str]["key"];
document.getElementById(Valueid).innerHTML=obj.web[str]["value"];
}
如果需要在普通页面使用,可以使用jsonp:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="css/mui.min.css" rel="stylesheet" />
</head>
<body>
<header class="mui-bar mui-bar-nav">
<a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
<h1 class="mui-title">native-JavaScript</h1>
</header>
<div class="mui-content mui-content-padded">
<div class="mui-input-row">
<label>输入关键词:</label>
<input id="input" type="text" placeholder="普通输入框">
</div>
<button id="btn" type="button" class="mui-btn mui-btn-blue mui-btn-block">翻译</button>
<div id="output"></div>
</div>
<script type="text/javascript">
var inputEl = document.querySelector("#input");
document.querySelector('#btn').addEventListener('click',function () {
var url = "http://fanyi.youdao.com/openapi.do";
var data = {
"keyfrom": "abc1243",
"key": "1207861310",
"type": "data",
"doctype": "jsonp",
"version": "1.1",
"q": inputEl.value,
"callback": "jsonpcallback"
}
var buffer = [];
for (var key in data) {
buffer.push(key + '=' + encodeURIComponent(data[key]));
}
var fullpath = url + '?' + buffer.join('&');
CreateScript(fullpath);
})
function CreateScript(src){
var el = document.createElement('script');
el.src = src;
el.async = true;
el.defer = true;
document.body.appendChild(el);
}
function jsonpcallback(rs) {
console.log(JSON.stringify(rs));
document.getElementById("output").innerHTML = JSON.stringify(rs);
}
</script>
</body>
</html>
第一步:在有道官方网站申请一个API key
举例:
API key:1207861310
keyfrom:abc1243
调用说明:
http://fanyi.youdao.com/openapi.do?keyfrom=<keyfrom>&key=<key>&type=data&doctype=<doctype>&version=1.1&q=要翻译的文本
版本:1.1,请求方式:get,编码方式:utf-8
主要功能:中英互译,同时获得有道翻译结果和有道词典结果(可能没有)
参数说明:
- type - 返回结果的类型,固定为data
- doctype - 返回结果的数据格式,xml或json或jsonp
- version - 版本,当前最新版本为1.1
- q - 要翻译的文本,必须是UTF-8编码,字符长度不能超过200个字符,需要进行urlencode编码
- only - 可选参数,dict表示只获取词典数据,translate表示只获取翻译数据,默认为都获取
注: 词典结果只支持中英互译,翻译结果支持英日韩法俄西到中文的翻译以及中文到英语的翻译
errorCode:
- 0 - 正常
- 20 - 要翻译的文本过长
- 30 - 无法进行有效的翻译
- 40 - 不支持的语言类型
- 50 - 无效的key
- 60 - 无词典结果,仅在获取词典结果生效
注意修改标记的四个地方,只需要修改q的值为你想要的翻译内容即可。
点击下方链接我们可以得到:
http://fanyi.youdao.com/openapi.do?keyfrom=abc1243&key=1207861310&type=data&doctype=json&version=1.1&q=翻译
可是网上多半就停留在此并没有告诉我们怎么在程序里面发出请求然后获取数据,之前找过一些例子,都是服务器端语言调用的,所以我误以为只能通过服务器端语言才能调用,结果一次在群里问了问,一个大神告诉说其实ajax就可以咯,于是之间就去找了找ajax的教程看了看,但是没怎么看懂,一大堆什么XMLHttpRequest 什么的,试了试还是各种理不清,找官方demo改了改,发现mui的ajax还是挺好懂的,格式也比较固定,对于菜鸟的我来说感觉这个才是最好的,不要先来一大堆没用的,废话少说,试试看就知道咯。
第二步:ajax跨域请求的简单实例
先来个最简单的直接点击按钮弹出返回的数据,只要这个成功了,那么改改还是很容易的。
【html部分】:
<button type="button" id="confirm" class="mui-btn mui-btn-royal mui-btn-block">发送请求</button>
【js部分】:
<script src="js/mui.min.js"></script>
<script>
//发送请求按钮的点击事件
document.getElementById("confirm").addEventListener('tap', function() {
var url = "http://fanyi.youdao.com/openapi.do?keyfrom=abc1243&key=1207861310&type=data&doctype=json&version=1.1&q=good";
mui.ajax(url,{
dataType:'json',//服务器返回json格式数据
type:'GET',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
//JSON.stringify()将 JSON对象转为json字符串
var data = JSON.stringify(data);
alert(data);
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
});
</script>
第三步:传递参数的ajax跨域请求
上面URL中把各种请求参数写固定了,不便于我们后期做修改,现在用ajax的data属性。
首先我们增加一个搜索输入框用于输入要翻译的内容:
修改html的代码如下:(样式文件没有引入,样式也没有写出来,主要是为了写清楚思路)
【html部分】
<form name="search" method="get">
<div class="mui-input-row mui-search input-search">
<input type="search" id="search" class="mui-input-speech mui-input-clear" placeholder="请输入内容...">
</div>
<button type="button" id="confirm" class="mui-btn mui-btn-royal mui-btn-block">发送请求</button>
</form>
【js部分】(修改部分的代码)
var search = document.getElementById("search");
//发送请求按钮的点击事件
document.getElementById("confirm").addEventListener('tap', function() {
var url = "http://fanyi.youdao.com/openapi.do";
mui.ajax(url,{
data:{
keyfrom:"abc1243",
key:"1207861310",
type:"data",
doctype:"json",
version:"1.1",
q:search.value
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
//JSON.stringify()将 JSON对象转为json字符串
var data = JSON.stringify(data);
alert(data);
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
});
第四步:ajax跨域请求怎么处理获取的数据
我们刚刚只是把数据alert出来了但是并没有进行任何后期操作,比如把有用信息获取写出来。
我们是把刚刚那个变成了json字符串alert出来的,也就是说是字符串而不是对象,获取键值对必须是对对象进行操作。
那么我们首先使用eval函数把json字符串转化成JavaScript对象:
//将json字符串转化成JavaScript对象
var obj = eval ("(" + response + ")");
然后我们就可以对obj对象进行操作了,json键值对的[] 中括号的使用如下:
JSON就是一串字符串 只不过元素会使用特定的符号标注。
- {} 双括号表示对象
- [] 中括号表示数组
- "" 双引号内是属性或值
- : 冒号表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
所以 {"name": "Michael"} 可以理解为是一个包含name为Michael的对象,而[{"name": "Michael"},{"name": "Jerry"}]就表示包含两个对象的数组。
var LangShen = {"Name":"Langshen","AGE":"28"};
这是一个json对象;{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数上面声明了一个名为“LangShen”的对象,多个属性或函数用,(逗号)隔开,因为是对象的属性,
那么我们访问的时候会有两种方式:
访问方式一:LangShen.Name、LangShen.AGE
访问方式二:LangShen["Name"]、LangShen["AGE"]
就是这么一个小小的方式,会有什么区别呢?
在实际应用中,第一种方式的.Name实际是作为一个对象被调用,而LangShen["Name"]里的name却可以是一个字符串。
有道翻译API获取实例:
我只是写出了基本思路,无非就是把对于内容写在对应的位置。
document.getElementById("translation").innerHTML=obj.translation;
document.getElementById("us-phonetic").innerHTML=obj.basic["us-phonetic"];
document.getElementById("phonetic").innerHTML=obj.basic["phonetic"];
document.getElementById("uk-phonetic").innerHTML=obj.basic["uk-phonetic"];
document.getElementById("explains").innerHTML=obj.basic["explains"];
document.getElementById("query").innerHTML=obj.query;
//遍历读取键值对写入
for(var str in obj.web){
var keyid=document.getElementsByName("webkey")[str].id;
var Valueid=document.getElementsByName("webvalue")[str].id;
document.getElementById(keyid).innerHTML=obj.web[str]["key"];
document.getElementById(Valueid).innerHTML=obj.web[str]["value"];
}
如果需要在普通页面使用,可以使用jsonp:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link href="css/mui.min.css" rel="stylesheet" />
</head>
<body>
<header class="mui-bar mui-bar-nav">
<a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
<h1 class="mui-title">native-JavaScript</h1>
</header>
<div class="mui-content mui-content-padded">
<div class="mui-input-row">
<label>输入关键词:</label>
<input id="input" type="text" placeholder="普通输入框">
</div>
<button id="btn" type="button" class="mui-btn mui-btn-blue mui-btn-block">翻译</button>
<div id="output"></div>
</div>
<script type="text/javascript">
var inputEl = document.querySelector("#input");
document.querySelector('#btn').addEventListener('click',function () {
var url = "http://fanyi.youdao.com/openapi.do";
var data = {
"keyfrom": "abc1243",
"key": "1207861310",
"type": "data",
"doctype": "jsonp",
"version": "1.1",
"q": inputEl.value,
"callback": "jsonpcallback"
}
var buffer = [];
for (var key in data) {
buffer.push(key + '=' + encodeURIComponent(data[key]));
}
var fullpath = url + '?' + buffer.join('&');
CreateScript(fullpath);
})
function CreateScript(src){
var el = document.createElement('script');
el.src = src;
el.async = true;
el.defer = true;
document.body.appendChild(el);
}
function jsonpcallback(rs) {
console.log(JSON.stringify(rs));
document.getElementById("output").innerHTML = JSON.stringify(rs);
}
</script>
</body>
</html>
收起阅读 »
![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/00/06/97_avatar_mid.jpg?v=1645774525)
iOS离线打包-支付插件配置
目前支付插件支持支付宝、微信支付和苹果内购支付:
支付插件首先需要到各开放平台申请帐号,申请查看该文档
配置使用的支付模块
参考该文档配置支付插件使用的库
支付宝
依赖库 | 系统库 | 资源文件 |
---|---|---|
liblibPayment.a,libalixpayment.a,AlipaySDK.framework | Security.framework,CoreMotion.framework,SystemConfiguration.framework,CFNetwork.framework,libc++.dylib | AlipaySDK.bundle |
微信支付
依赖库 | 系统库 | 资源文件 |
---|---|---|
liblibPayment.a, libwxpay.a, libWeChatSDK_pay.a | libsqlite3.0.dylib, libz.dylib, CoreTelephony.framework, SystemConfiguration.framework |
配置支付平台参数
feature.plist 配置
在工程中搜索 feature.plist 文件(位于PandoraApi.bundle中),在 Payment-> extend 节点下添加对应平台的配置
支付宝
在URL Types 中添加配置: identifier 填写 alixpay ,URL Schemes 填写 alix[后面是您在支付宝平台申请的appid] ,如果没有该项按照图中的格式创建
注意:
iOS9.0以上版本需要在info.plist增加以下配置
微信支付
在URL Types 中添加配置: identifier 填写 weixin ,URL Schemes 填写wx[后面是您在微信平台申请的appkey] ,如果没有该项按照图中的格式创建
注意:
<a id="ulink"/>
HBuilderX2.3.4+ 版本需要配置 Universal Link
在info.plist root 节点添加UniversalLinks项,值和微信开放平台配置的一致,参考如下:
查看工程里的AppDelegate.m文件里是否有下面的方法:
>//@Summary:通用链接
-(BOOL)application:(UIApplication )application continueUserActivity:(NSUserActivity )userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler {
[PDRCore handleSysEvent:PDRCoreSysEventContinueUserActivity withObject:userActivity];
restorationHandler(nil);
return YES;
}
注意:
iOS9.0以上版本需要在info.plist增加以下配置
目前支付插件支持支付宝、微信支付和苹果内购支付:
支付插件首先需要到各开放平台申请帐号,申请查看该文档
配置使用的支付模块
参考该文档配置支付插件使用的库
支付宝
依赖库 | 系统库 | 资源文件 |
---|---|---|
liblibPayment.a,libalixpayment.a,AlipaySDK.framework | Security.framework,CoreMotion.framework,SystemConfiguration.framework,CFNetwork.framework,libc++.dylib | AlipaySDK.bundle |
微信支付
依赖库 | 系统库 | 资源文件 |
---|---|---|
liblibPayment.a, libwxpay.a, libWeChatSDK_pay.a | libsqlite3.0.dylib, libz.dylib, CoreTelephony.framework, SystemConfiguration.framework |
配置支付平台参数
feature.plist 配置
在工程中搜索 feature.plist 文件(位于PandoraApi.bundle中),在 Payment-> extend 节点下添加对应平台的配置
支付宝
在URL Types 中添加配置: identifier 填写 alixpay ,URL Schemes 填写 alix[后面是您在支付宝平台申请的appid] ,如果没有该项按照图中的格式创建
注意:
iOS9.0以上版本需要在info.plist增加以下配置
微信支付
在URL Types 中添加配置: identifier 填写 weixin ,URL Schemes 填写wx[后面是您在微信平台申请的appkey] ,如果没有该项按照图中的格式创建
注意:
<a id="ulink"/>
HBuilderX2.3.4+ 版本需要配置 Universal Link
在info.plist root 节点添加UniversalLinks项,值和微信开放平台配置的一致,参考如下:
查看工程里的AppDelegate.m文件里是否有下面的方法:
>//@Summary:通用链接
-(BOOL)application:(UIApplication )application continueUserActivity:(NSUserActivity )userActivity restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler {
[PDRCore handleSysEvent:PDRCoreSysEventContinueUserActivity withObject:userActivity];
restorationHandler(nil);
return YES;
}
注意:
iOS9.0以上版本需要在info.plist增加以下配置
![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/03/14/74_avatar_mid.jpg?v=0)
分享基于plus.storage的角标管理类,主要用于触发个推消息监听事件后设置角标v1.0.2
今天下午做个推消息推送,需要提醒卖家“你有1笔新的付款订单到账,请及时处理”。
因此需要将数字保存,然后在收到个推推送后,设置订单管理的角标+1,应用的角标+1。
类似下面的效果:
大家都知道角标肯定是数字的,然后使用plus.storage.setItem保存,再使用plus.storage.getItem获取,就是始终获取不到。
折腾了一下午,结果发现plus.storage.setItem只能保存string类型的数据,http://ask.dcloud.net.cn/question/6474
说多了都是泪啊 T_T
遂将角标管理类分享出来,也帮着填一个坑,已自动将value转换为string,保存到plus.storage。欢迎各位拍砖!
注意:
5+设置角标API plus.runtime.setBadgeNumber,官方文档是这么描述的:
Android - 2.2+ (支持): 目前仅支持小米(MIUI v5),其它设备调用后无任何效果;
iOS - 4.3+ (支持): 应用需开启“Push Notifications”服务才生效。
暂不知道官方的支持计划。
// 用法1.
plus.push.addEventListener('receive', function(msg){
if(msg.aps){
alert('接收到在线APNS消息');
}else{
alert('接收到在线透传消息');
}
// 测试在线,透传消息,设置角标
BadgeManager.setInc('order', 1);
})
// 用法2.
// 进入订单管理模块后,清除订单角标
BadgeManager.removeBadgeNumber('order');
/**
* BadgeManager 静态类
* 只需要关心对应业务的角标增长值,自动计算总的角标数,并设置App角标plus.runtime.setBadgeNumber
* @author fanrong33
* @version 1.0.2 build 201501223
*/
;function BadgeManager(){
};
/**
* 角标增长
* @param {String} key 键值
* @param {Number} step 增长值
*/
BadgeManager.setInc = function(key, step){
var key = "badge_"+key;
var total_number = plus.storage.getItem("badge_total_number");
var key_number = plus.storage.getItem(key);
total_number = parseInt(total_number); // 字符串转数字
key_number = parseInt(key_number);
if(!key_number) key_number = 0;
if(!total_number) total_number = 0;
key_number = key_number + step;
total_number = total_number + step;
plus.storage.setItem(key, key_number.toString()); // 数字转字符串
plus.storage.setItem("badge_total_number", total_number.toString());
// 设置APP图标的角标
plus.runtime.setBadgeNumber(total_number);
}
/**
* 角标减少
* @param {String} key 键值
* @param {Number} step 减少值
*/
BadgeManager.setDec = function(key, step){
var key = "badge_"+key;
var total_number = plus.storage.getItem("badge_total_number");
var key_number = plus.storage.getItem(key);
total_number = parseInt(total_number);
key_number = parseInt(key_number);
if(!key_number) key_number = 0;
if(!total_number) total_number = 0;
key_number = key_number - step;
total_number = total_number - step;
if(key_number < 0) key_number = 0;
if(total_number < 0) total_number = 0;
plus.storage.setItem(key, key_number.toString());
plus.storage.setItem("badge_total_number", total_number.toString());
// 设置APP图标的角标
plus.runtime.setBadgeNumber(total_number);
}
/**
* 根据key获取对应的角标值
* @param {String} key
*/
BadgeManager.getBadgeNumber = function(key){
var key = "badge_"+key;
var key_number = plus.storage.getItem(key);
key_number = parseInt(key_number);
if(!key_number) key_number = 0;
return key_number;
}
/**
* 删除key对应的角标值
* @param {String} key
*/
BadgeManager.removeBadgeNumber = function(key){
var key = "badge_"+key;
var total_number = plus.storage.getItem("badge_total_number");
var key_number = plus.storage.getItem(key);
total_number = parseInt(total_number);
key_number = parseInt(key_number);
if(!key_number) key_number = 0;
if(!total_number) total_number = 0;
total_number = total_number - key_number;
if(total_number < 0) total_number = 0;
plus.storage.removeItem(key);
plus.storage.setItem("badge_total_number", total_number.toString());
// 设置APP图标的角标
plus.runtime.setBadgeNumber(total_number);
}
今天下午做个推消息推送,需要提醒卖家“你有1笔新的付款订单到账,请及时处理”。
因此需要将数字保存,然后在收到个推推送后,设置订单管理的角标+1,应用的角标+1。
类似下面的效果:
大家都知道角标肯定是数字的,然后使用plus.storage.setItem保存,再使用plus.storage.getItem获取,就是始终获取不到。
折腾了一下午,结果发现plus.storage.setItem只能保存string类型的数据,http://ask.dcloud.net.cn/question/6474
说多了都是泪啊 T_T
遂将角标管理类分享出来,也帮着填一个坑,已自动将value转换为string,保存到plus.storage。欢迎各位拍砖!
注意:
5+设置角标API plus.runtime.setBadgeNumber,官方文档是这么描述的:
Android - 2.2+ (支持): 目前仅支持小米(MIUI v5),其它设备调用后无任何效果;
iOS - 4.3+ (支持): 应用需开启“Push Notifications”服务才生效。
暂不知道官方的支持计划。
// 用法1.
plus.push.addEventListener('receive', function(msg){
if(msg.aps){
alert('接收到在线APNS消息');
}else{
alert('接收到在线透传消息');
}
// 测试在线,透传消息,设置角标
BadgeManager.setInc('order', 1);
})
// 用法2.
// 进入订单管理模块后,清除订单角标
BadgeManager.removeBadgeNumber('order');
/**
* BadgeManager 静态类
* 只需要关心对应业务的角标增长值,自动计算总的角标数,并设置App角标plus.runtime.setBadgeNumber
* @author fanrong33
* @version 1.0.2 build 201501223
*/
;function BadgeManager(){
};
/**
* 角标增长
* @param {String} key 键值
* @param {Number} step 增长值
*/
BadgeManager.setInc = function(key, step){
var key = "badge_"+key;
var total_number = plus.storage.getItem("badge_total_number");
var key_number = plus.storage.getItem(key);
total_number = parseInt(total_number); // 字符串转数字
key_number = parseInt(key_number);
if(!key_number) key_number = 0;
if(!total_number) total_number = 0;
key_number = key_number + step;
total_number = total_number + step;
plus.storage.setItem(key, key_number.toString()); // 数字转字符串
plus.storage.setItem("badge_total_number", total_number.toString());
// 设置APP图标的角标
plus.runtime.setBadgeNumber(total_number);
}
/**
* 角标减少
* @param {String} key 键值
* @param {Number} step 减少值
*/
BadgeManager.setDec = function(key, step){
var key = "badge_"+key;
var total_number = plus.storage.getItem("badge_total_number");
var key_number = plus.storage.getItem(key);
total_number = parseInt(total_number);
key_number = parseInt(key_number);
if(!key_number) key_number = 0;
if(!total_number) total_number = 0;
key_number = key_number - step;
total_number = total_number - step;
if(key_number < 0) key_number = 0;
if(total_number < 0) total_number = 0;
plus.storage.setItem(key, key_number.toString());
plus.storage.setItem("badge_total_number", total_number.toString());
// 设置APP图标的角标
plus.runtime.setBadgeNumber(total_number);
}
/**
* 根据key获取对应的角标值
* @param {String} key
*/
BadgeManager.getBadgeNumber = function(key){
var key = "badge_"+key;
var key_number = plus.storage.getItem(key);
key_number = parseInt(key_number);
if(!key_number) key_number = 0;
return key_number;
}
/**
* 删除key对应的角标值
* @param {String} key
*/
BadgeManager.removeBadgeNumber = function(key){
var key = "badge_"+key;
var total_number = plus.storage.getItem("badge_total_number");
var key_number = plus.storage.getItem(key);
total_number = parseInt(total_number);
key_number = parseInt(key_number);
if(!key_number) key_number = 0;
if(!total_number) total_number = 0;
total_number = total_number - key_number;
if(total_number < 0) total_number = 0;
plus.storage.removeItem(key);
plus.storage.setItem("badge_total_number", total_number.toString());
// 设置APP图标的角标
plus.runtime.setBadgeNumber(total_number);
}
收起阅读 »
![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/10/34/15_avatar_mid.jpg?v=0)
离线打包添加友盟SDK、点乐积分墙
dCloud的文档,没有搜索功能,真的不方便,求加,如果没有人手,我可以帮解决
刚开始用dcloud一天,以下功能是我昨天下午折腾出来的,大约用了五个小时,测试了以下两个功能,均正常
- mac中无法识别魅族4的测试机,处理方法如下
修改文件 ~/.android/adb_usb.ini,在文件开头或末尾添加一行,内容是0x2a45。
adb kill-server
adb devices
-
将DCloud完整包导入adt,保证DCloud Hello项目可完整运行,流程如下:
http://ask.dcloud.net.cn/docs#http://ask.dcloud.net.cn/article/38 -
下载点乐积分墙,将sdk中的jar包解压出来,放到/libs/dlnetwork.jar
-
按点乐的文档,AndroidManifest.xml中添加好权限和service,然后在DCLOUD中新建页面,调用点乐积分墙,代码如下:
function dianle(){
mainActivity = plus.android.runtimeMainActivity();
dlnetwork = plus.android.importClass("com.dlnetwork.DevInit");
var d = new dlnetwork();
d.initGoogleContext(mainActivity, '34db9f40428a12701ad2738999b197ca', 'MY_CHANNLE_NAME');
d.showOffers(mainActivity);
}
- Dcloud中已经集成了umeng的云打包,离线打包的时候或者想统计指定页面的,手工调用代码如下:
function plusReady(){ //这里是其它初始化代码 //友盟统计 mainActivity = plus.android.runtimeMainActivity(); MobclickAgent = plus.android.importClass("com.umeng.analytics.MobclickAgent"); MobclickAgent.onPageStart("MainScreen"); }
via:http://www.4wei.cn/archives/1002483
dCloud的文档,没有搜索功能,真的不方便,求加,如果没有人手,我可以帮解决
刚开始用dcloud一天,以下功能是我昨天下午折腾出来的,大约用了五个小时,测试了以下两个功能,均正常
- mac中无法识别魅族4的测试机,处理方法如下
修改文件 ~/.android/adb_usb.ini,在文件开头或末尾添加一行,内容是0x2a45。
adb kill-server
adb devices
-
将DCloud完整包导入adt,保证DCloud Hello项目可完整运行,流程如下:
http://ask.dcloud.net.cn/docs#http://ask.dcloud.net.cn/article/38 -
下载点乐积分墙,将sdk中的jar包解压出来,放到/libs/dlnetwork.jar
-
按点乐的文档,AndroidManifest.xml中添加好权限和service,然后在DCLOUD中新建页面,调用点乐积分墙,代码如下:
function dianle(){
mainActivity = plus.android.runtimeMainActivity();
dlnetwork = plus.android.importClass("com.dlnetwork.DevInit");
var d = new dlnetwork();
d.initGoogleContext(mainActivity, '34db9f40428a12701ad2738999b197ca', 'MY_CHANNLE_NAME');
d.showOffers(mainActivity);
}
- Dcloud中已经集成了umeng的云打包,离线打包的时候或者想统计指定页面的,手工调用代码如下:
function plusReady(){ //这里是其它初始化代码 //友盟统计 mainActivity = plus.android.runtimeMainActivity(); MobclickAgent = plus.android.importClass("com.umeng.analytics.MobclickAgent"); MobclickAgent.onPageStart("MainScreen"); }
via:http://www.4wei.cn/archives/1002483
收起阅读 »![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/00/00/57_avatar_mid.jpg?v=0)
APICloud项目如何快速迁移到DCloud下
概述
最近很多新来的开发者问到一个问题:我之前用过APICloud,现在想改用DCloud产品,我原来的App是否可方便迁移?
迁移肯定是可以的,这里我们系统的讲下产品的区别和迁移的思路。
首先大家需要了解DCloud的产品,包括:
HBuilder:快速编码、调试、打包的IDE。它可以开发各种HTML5类程序,pc网站或app都可以开发,前端常见的less、sass等程序也可以开发。还可以通过插件开发php等语言。
5+ Runtime:基于webview的增强runtime,扩展了大量的js api,打通原生api和js api的桥梁。
5+ Runtime包括2部分,HTML5plus规范和Native.js。体验该产品请点这里下载手机demohttp://www.dcloud.io/helloh5
相比于APICloud的客户端,5+Runtime的能力更强大、开放性更好。
mui:一个开源、适用于手机App的、高性能前端框架。在App开发中是属于可选但推荐使用的框架。mui大部分基于HTML5实现,一些HTML5实现起来体验不好的地方,会调用5+ runtime的原生扩展能力实现。同时mui也可用于开发手机浏览器web app或微信app。体验该产品请点这里下载手机demohttp://www.dcloud.io/hellomui
更多了解这3个产品,请仔细阅读:
- DCloud产品概述
- mui概述:从本文中大家可以了解mui的设计理念,理解mui仅偏重ui组件、不封装各种util方法的“有所为、有所不为”的思想;
然后大家应该仔细阅读如下这篇产品设计对比文章:
- APICloud产品与DCloud深度对比分析:大家可从本文中了解APICloud产品和DCoud产品的深层次差异;
了解一下基础概念后,接下来从APICloud开发者的既有认知角度出发,介绍从APICloud向DCloud技术迁移的注意事项。
标准H5部分可直接迁移
所有基于标准HTML5开发的js、css、html,两个平台一致,可无缝迁移;所有基于H5封装的第三方组件(注意这里是第三方H5组件,不是APICloud官方封装的标准组件),均可平滑迁移;
扩展API对象--UI部分
域
APICloud的api都是以api.开头,是其公司的私有api。
DCloud的5+ runtime,命名以plus.开头;
DCloud的mui前端框架的api以mui.开头。
举个例子,打开窗口,APICloud是api.OpenWin;5+是plus.webview.open;mui是mui.openWindow。
当然mui.openWindow也是对plus.webview.open的一种封装,并且在里面处理了各种常见业务,比如显示/关闭waiting雪花。
窗口系统
两家的窗口都是基于原生的webview的,封装的命名略有不同;
APICloud在api命名层面就区分主窗口和子窗口,分别封装了api.OpenWin和api.OpenFrame两个方法;
而DCloud的5+ runtime是统一的plus.webview对象处理;通过plus.webview.create方法可创建webview,在该方法中通过参数控制webview显示位置;如果是要把一个子窗口嵌入父窗口,使用webview对象的append方法。
mui为了简化书写,封装了mui.openWindow方法,通过该方法可以创建并显示webview对象;通过mui.init方法中的subpages参数,可以创建子webview;
APICloud特意封装了api.openSlidLayout、api.openSlidPane等方法来实现侧滑导航;
mui的侧滑实现更为自由,就是滑动一个webview或一个div,不需要单独的方法。
- webview模式:移动整个webview;
- div模式:移动div区域;
每种模式下又有不同的动画效果,主要有3类:
- 主窗口不动、菜单移动;
- 菜单不动、主窗口移动;
- 主窗口、菜单同时移动;
mui封装的div模式侧滑菜单,用户无需任何js干预,仅需按照特定结构书写html即可,详细规范参考mui官网。
UI组件
APICloud原生封装的alert、confirm、prompt、actionSheet、toast、showProgress(对应DCloud公司的showWaiting)等,DCloud公司的5+ runtime也对应做了原生封装,参考nativeUI规范;
此时把api.alert改为plus.nativeUI.alert或mui.alert极客。
另外,DCloud公司的mui前端框架,还针对部分组件实现了更易个性化定制的H5版本,比如:actionSheet、toast、openPicker(对应mui中的dtPicker),可直接从hello mui中查看示例;
APICloud还封装了原生的按钮、输入框等控件,这些控件HTML自己就有,而且也没有性能问题,我们认为这些封装没有意义,并且原生控件会导致很难定位排版及无法个性化样式。
导航菜单
navigationBar
APICloud通过原生封装navigationBar对象,实现可滑动的导航条效果;DCloud则通过标准H5实现的分段选择,具有同等效果,且样式更为丰富;参考hello mui示例中的segment(分段选择),如下为两张效果图:
tabBar
tabBar是一个底部选项卡组件,APICloud通过js动态生成该组件;mui同样封装了选项卡组件,但通过简单html即可生成,在HBuilder中输入mtab即可生成选项卡的代码块;同时hello mui提供了多种选项卡模式,例如:webview模式选项卡、div模式选项卡、仅文字选项卡、二级选项卡;
界面布局
button
APICloud封装了原生的按钮,其实HTML自己就有按钮,封装原生按钮多此一举。
mui对HTML的按钮做了样式美化,提供各种颜色风格的按钮,只需如下简单一行html即可生成一个蓝色按钮:
<input type="button" class="mui-btn mui-btn-blue">
mui的按钮添加不同class即可实现更多风格,效果如如下:
citySelector
APICloud封装了一个原生citySelector组件,通过js调用生成;
DCloud公司则通过H5封装了一个popPicker组件,通过该组件,既可以实现城市选择,也可以实现日期时间选择;参考hello mui中对应示例,效果图如下:
listview
mui通过H5封装了列表组件,在HBuilder中输入mList并回车,就可以快速生成列表代码块,简单几行html,实现一个列表组件,代码如下:
<ul class="mui-table-view">
<li class="mui-table-view-cell">
<a class="mui-navigate-right">
Item 1
</a>
</li>
</ul>
mui同样支持左右滑动列表项显示功能按钮;同时,mui还封装了各种其它组件,比如二级列表、图文列表等,详细参考hello mui示例;
scrollPicture
APICloud封装的图片联播器,对应着mui封装的gallery slider(图片轮播)组件,按照特定格式写一段标准的html,就会自动生成图片轮播组件;关于图片轮播的详细介绍,参考mui官网;
slider
APICloud原生封装的滑动器,对应着mui框架中的range(滑块),好的前端一样可以写出媲美原生体验的滑块组件,且使用更简单,仅需如下3行代码:
<div class="mui-input-row mui-input-range">
<input type="range" id='block-range' value="50" min="0" max="100" >
</div>
mui封装的滑块效果图如下:
timeSelector
参考citySelector,对应mui封装的popPicker组件;hello mui中也单独针对时间,给出了原生和H5两种示例;
DCloud公司的mui框架封装的其它组件
mui封装了更多灵活的mobile前端组件,如下:
- accordion(折叠面板)
- switch(开关)
- popover(弹出菜单)
- radio(单选框)
- checkbox(复选框)
- input(输入框) -- 支持清空操作、语音输入
- grid(9宫格)
更新:uni-app项目迁移
以上文档讲述的是apicloud项目迁移到5+app。如果是喜欢uni-app,那没法迁移,需要按uni-app的规范重新开发。
概述
最近很多新来的开发者问到一个问题:我之前用过APICloud,现在想改用DCloud产品,我原来的App是否可方便迁移?
迁移肯定是可以的,这里我们系统的讲下产品的区别和迁移的思路。
首先大家需要了解DCloud的产品,包括:
HBuilder:快速编码、调试、打包的IDE。它可以开发各种HTML5类程序,pc网站或app都可以开发,前端常见的less、sass等程序也可以开发。还可以通过插件开发php等语言。
5+ Runtime:基于webview的增强runtime,扩展了大量的js api,打通原生api和js api的桥梁。
5+ Runtime包括2部分,HTML5plus规范和Native.js。体验该产品请点这里下载手机demohttp://www.dcloud.io/helloh5
相比于APICloud的客户端,5+Runtime的能力更强大、开放性更好。
mui:一个开源、适用于手机App的、高性能前端框架。在App开发中是属于可选但推荐使用的框架。mui大部分基于HTML5实现,一些HTML5实现起来体验不好的地方,会调用5+ runtime的原生扩展能力实现。同时mui也可用于开发手机浏览器web app或微信app。体验该产品请点这里下载手机demohttp://www.dcloud.io/hellomui
更多了解这3个产品,请仔细阅读:
- DCloud产品概述
- mui概述:从本文中大家可以了解mui的设计理念,理解mui仅偏重ui组件、不封装各种util方法的“有所为、有所不为”的思想;
然后大家应该仔细阅读如下这篇产品设计对比文章:
- APICloud产品与DCloud深度对比分析:大家可从本文中了解APICloud产品和DCoud产品的深层次差异;
了解一下基础概念后,接下来从APICloud开发者的既有认知角度出发,介绍从APICloud向DCloud技术迁移的注意事项。
标准H5部分可直接迁移
所有基于标准HTML5开发的js、css、html,两个平台一致,可无缝迁移;所有基于H5封装的第三方组件(注意这里是第三方H5组件,不是APICloud官方封装的标准组件),均可平滑迁移;
扩展API对象--UI部分
域
APICloud的api都是以api.开头,是其公司的私有api。
DCloud的5+ runtime,命名以plus.开头;
DCloud的mui前端框架的api以mui.开头。
举个例子,打开窗口,APICloud是api.OpenWin;5+是plus.webview.open;mui是mui.openWindow。
当然mui.openWindow也是对plus.webview.open的一种封装,并且在里面处理了各种常见业务,比如显示/关闭waiting雪花。
窗口系统
两家的窗口都是基于原生的webview的,封装的命名略有不同;
APICloud在api命名层面就区分主窗口和子窗口,分别封装了api.OpenWin和api.OpenFrame两个方法;
而DCloud的5+ runtime是统一的plus.webview对象处理;通过plus.webview.create方法可创建webview,在该方法中通过参数控制webview显示位置;如果是要把一个子窗口嵌入父窗口,使用webview对象的append方法。
mui为了简化书写,封装了mui.openWindow方法,通过该方法可以创建并显示webview对象;通过mui.init方法中的subpages参数,可以创建子webview;
APICloud特意封装了api.openSlidLayout、api.openSlidPane等方法来实现侧滑导航;
mui的侧滑实现更为自由,就是滑动一个webview或一个div,不需要单独的方法。
- webview模式:移动整个webview;
- div模式:移动div区域;
每种模式下又有不同的动画效果,主要有3类:
- 主窗口不动、菜单移动;
- 菜单不动、主窗口移动;
- 主窗口、菜单同时移动;
mui封装的div模式侧滑菜单,用户无需任何js干预,仅需按照特定结构书写html即可,详细规范参考mui官网。
UI组件
APICloud原生封装的alert、confirm、prompt、actionSheet、toast、showProgress(对应DCloud公司的showWaiting)等,DCloud公司的5+ runtime也对应做了原生封装,参考nativeUI规范;
此时把api.alert改为plus.nativeUI.alert或mui.alert极客。
另外,DCloud公司的mui前端框架,还针对部分组件实现了更易个性化定制的H5版本,比如:actionSheet、toast、openPicker(对应mui中的dtPicker),可直接从hello mui中查看示例;
APICloud还封装了原生的按钮、输入框等控件,这些控件HTML自己就有,而且也没有性能问题,我们认为这些封装没有意义,并且原生控件会导致很难定位排版及无法个性化样式。
导航菜单
navigationBar
APICloud通过原生封装navigationBar对象,实现可滑动的导航条效果;DCloud则通过标准H5实现的分段选择,具有同等效果,且样式更为丰富;参考hello mui示例中的segment(分段选择),如下为两张效果图:
tabBar
tabBar是一个底部选项卡组件,APICloud通过js动态生成该组件;mui同样封装了选项卡组件,但通过简单html即可生成,在HBuilder中输入mtab即可生成选项卡的代码块;同时hello mui提供了多种选项卡模式,例如:webview模式选项卡、div模式选项卡、仅文字选项卡、二级选项卡;
界面布局
button
APICloud封装了原生的按钮,其实HTML自己就有按钮,封装原生按钮多此一举。
mui对HTML的按钮做了样式美化,提供各种颜色风格的按钮,只需如下简单一行html即可生成一个蓝色按钮:
<input type="button" class="mui-btn mui-btn-blue">
mui的按钮添加不同class即可实现更多风格,效果如如下:
citySelector
APICloud封装了一个原生citySelector组件,通过js调用生成;
DCloud公司则通过H5封装了一个popPicker组件,通过该组件,既可以实现城市选择,也可以实现日期时间选择;参考hello mui中对应示例,效果图如下:
listview
mui通过H5封装了列表组件,在HBuilder中输入mList并回车,就可以快速生成列表代码块,简单几行html,实现一个列表组件,代码如下:
<ul class="mui-table-view">
<li class="mui-table-view-cell">
<a class="mui-navigate-right">
Item 1
</a>
</li>
</ul>
mui同样支持左右滑动列表项显示功能按钮;同时,mui还封装了各种其它组件,比如二级列表、图文列表等,详细参考hello mui示例;
scrollPicture
APICloud封装的图片联播器,对应着mui封装的gallery slider(图片轮播)组件,按照特定格式写一段标准的html,就会自动生成图片轮播组件;关于图片轮播的详细介绍,参考mui官网;
slider
APICloud原生封装的滑动器,对应着mui框架中的range(滑块),好的前端一样可以写出媲美原生体验的滑块组件,且使用更简单,仅需如下3行代码:
<div class="mui-input-row mui-input-range">
<input type="range" id='block-range' value="50" min="0" max="100" >
</div>
mui封装的滑块效果图如下:
timeSelector
参考citySelector,对应mui封装的popPicker组件;hello mui中也单独针对时间,给出了原生和H5两种示例;
DCloud公司的mui框架封装的其它组件
mui封装了更多灵活的mobile前端组件,如下:
- accordion(折叠面板)
- switch(开关)
- popover(弹出菜单)
- radio(单选框)
- checkbox(复选框)
- input(输入框) -- 支持清空操作、语音输入
- grid(9宫格)
更新:uni-app项目迁移
以上文档讲述的是apicloud项目迁移到5+app。如果是喜欢uni-app,那没法迁移,需要按uni-app的规范重新开发。
收起阅读 »![](https://img-cdn-tc.dcloud.net.cn/account/identicon/8fce0ca3c812afce8e43c8cbba769a75.png)
webview侧滑菜单使用注意事项
设有父页面A,带侧滑菜单的子页面B,应给子页面B设置zindex大于侧滑菜单zindex值,否则在直接按back键返回父页面A时,会发生错位
设有父页面A,带侧滑菜单的子页面B,应给子页面B设置zindex大于侧滑菜单zindex值,否则在直接按back键返回父页面A时,会发生错位
![](https://img-cdn-tc.dcloud.net.cn/account/identicon/022034aeedc39446e3e20a4e751fb617.png)
开始使用 HBuilder 和 Mui - 1 - 分析 index.html ;
好吧,在比较了 Codenameone 和 HBuilder 以后,俺反复考虑后,终于还是决定使用 HBuilder 这个东东;
简单说说 Codenameone 吧,用 java 进行开发的跨平台(注意,目前支持 android, ios, wp, BlackBerry) 的框架,首先吸引我的是它的跨平台移动开发能力, 其次吧,编译型的语言比较好进行TDD开发, 第三,有一个可视化的界面设计环境以及界面设计和处理代码相分离的处理逻辑,第四,无需虚拟机直接可以在本地的JAVA IDE中运行进行测试和调试;
但是,讨厌的几个问题是,1.需要翻墙, 2.文档全E文, 3. 除了API之外,基本没有文档;
好吧,闲话少说,开始使用 HBuilder;
俺就不吐槽文档MUI文档缺少的问题了;(建议首先一定要仔细看 mui 的那个文档至少3遍,对于里面的所有变量定义有一个大致印象,否则,对于比较喜欢寻根究底的人(比如说我)来说,会比较辛苦);
先创建一个 HelloMUI 的例子项目;在手机上运行,很好;在AVD的模拟器上运行,也很好;
用 chrome 浏览器连接真机想Inspect进行调试,已经看到打开哪些网页l了,但就是Inspect不了,好吧,我的手机是红米,目前是4.2,需要4.4.2才支持;
用 chrome 浏览器连接AVD的虚拟机来Inspect进行调试,同样看到打开哪些网页l了,但就是Inspect不了,好吧,翻墙,给 chrome安装上ADB插件,还是 Inspect不了;
好吧,安装上了一个号称快得多的Genymotion,再下了一个4.4.4的镜像,终于可以用chrome注入进行代码调试了;
但是,谁说额Genymotion速度要快的啊?除了虚拟机启动速度快那么一点意外,
俺的I7、8G内存跑HelloMui无论是启动速度还是响应速度,比起安装上 InterHAXL 再加 Inter ATOM 的虚拟机速度慢的实在太多了;
好吧,俺忍。。。。等 魅蓝Note2 出来俺就换手机;
开始仔细看 index.html 的代码和 List.html 的代码;
好吧,目前为止 , 可以知道 mui.init 里面那个object带的属性有:
swipeBack:true //启用右滑关闭功能
statusBarBackground: '#f7f7f7',
gestureConfig:{
doubletap:true
},
subpages: [{
id: 'list',
url: 'list.html',
styles: {
top: '45px',
bottom: 0,
bounce: 'vertical'
}
},
styles:{ .... }
那么 statusBarBackground 这个参数是干啥的呢?貌似是状态栏的背景颜色,有没有其他类似的其他属性呢?不知道;
甚至, statusBarBackground 这个属性在 MUI自己的API文档里提都没有提到过,是我在 index.html的第27行里面翻出来的;
好吧,继续往下看, mui.os 这个又什么东东?继续翻API,很遗憾,还是没有;
看 HBuilder的提示, mui里面有 ajaxSetting, data, fn, os, gestures, options 。等几个属性,好吧,大家暂时记得 mui.os 里面记录了操作系统的一些环境变量的定义就可以了;至于其他属性,大家就当没有看到吧;
那个弹出菜单因为俺估计用不到,所以嘛,就跳过了;
继续往下看,到了显示关于 页面的处理了;
俺贴出代码吧,
document.getElementById('info').addEventListener('tap', function() {
if (subWebview == null) {
//获取共用父窗体
template = plus.webview.getWebviewById("default-main");
}
if(template){
subWebview = template.children()[0];
subWebview.loadURL('examples/info.html');
//修改共用父模板的标题
mui.fire(template, 'updateHeader', {
title: '关于XXXX',
showMenu: false
});
template.show('slide-in-right', 150);
}
});
plus.webview.getWebviewById("default-main"); 这个 default-main 是啥东东??
开 MUI API文档,没有; 看 H5 Api文档,还是没有;整个项目查找, 稀奇了,还是没有:
好吧,俺承认失败了,姑且认为 default-main 是整个程序第一个加载的页面吧;(这个看法是错误的,稍后会说明);
继续往下看,没有其他需要注意的地方了;真的没有了?
template.children()[0] 这个是啥东东,问题回到原点,归根结底还是需要知道 plus.webview.getWebviewById("default-main") 是什么东东;
暂时放下这个问题, subWebview.loadURL('examples/info.html'); 这个没有疑问;
//修改共用父模板的标题
mui.fire(template, 'updateHeader', {
title: '关于XXXX',
showMenu: false
});
template.show('slide-in-right', 150);
很简单吧?没有这么简单;大家打开 examples/info.html 这个页面,会发现里面也定义了 Header,俺比较偏执,总觉得这儿不应该定义 Header,于是就把 info.html 页面里面的 Header 给注释掉了,呵呵,果然标题照样给改掉了;
说明什么?说明, mui.fire(template, 'updateHeader' 这个修改的不是 info.html 里面 Header 定义的标题;
好吧,打开 关于 页面,再按 Back 按钮,首页标题还是 Hello mui,
说明什么?说明,mui.fire(template, 'updateHeader' 这个修改的不是 index.html 里面 Header 定义的标题;
那么到底修改的是哪儿的Header的内容?
再次打开 关于 页面,可以发现 页面切换时会显示 加载中 这三个字;本来我以为这个是 mui 在页面切换时的自动提示,但还是在整个项目中搜了一下,居然发现在 example/template.html 中有这个三个字,怀着好奇的心情,俺把这三个字改成了 TMD , 结果,呵呵,页面切换时果然显示了 TMD ;
好吧,俺服了;继续找 template.html 在哪儿被引用;
list.html 中有这样的定义: getTemplate('default', 'examples/template.html'); 再看 getTemplate的方法定义,
var headerWebview = mui.preload({
url:header,
id:name "-main",
styles:{
popGesture:"hide",
},
extras:{
mType: 'main'
}
});
终于,俺们找到了 default-main 是在哪儿定义的了;
再看下面的代码,headerWebview.append(subWebview); 终于也找到 template.children()[0] 是啥东东了。。。
说到这儿,大家以为完了?哪有这么简单;
subWebview.loadURL('examples/info.html'); 大家还记得吧,上面我把 info.html 的 Header部分注释掉了,现在俺把 Header 给改回来,
那么 这个 subWebview 加载的页面应该也包含有 一个 Header, 可是这个 info.html 里面的这个 Header 无论如何也不会显示出来?
现在,问题来了,这个 Header 到底到哪儿去了?
暂时就这样了;
经过这个这个分析,俺有些怀疑自己的选择了。。。
好吧,在比较了 Codenameone 和 HBuilder 以后,俺反复考虑后,终于还是决定使用 HBuilder 这个东东;
简单说说 Codenameone 吧,用 java 进行开发的跨平台(注意,目前支持 android, ios, wp, BlackBerry) 的框架,首先吸引我的是它的跨平台移动开发能力, 其次吧,编译型的语言比较好进行TDD开发, 第三,有一个可视化的界面设计环境以及界面设计和处理代码相分离的处理逻辑,第四,无需虚拟机直接可以在本地的JAVA IDE中运行进行测试和调试;
但是,讨厌的几个问题是,1.需要翻墙, 2.文档全E文, 3. 除了API之外,基本没有文档;
好吧,闲话少说,开始使用 HBuilder;
俺就不吐槽文档MUI文档缺少的问题了;(建议首先一定要仔细看 mui 的那个文档至少3遍,对于里面的所有变量定义有一个大致印象,否则,对于比较喜欢寻根究底的人(比如说我)来说,会比较辛苦);
先创建一个 HelloMUI 的例子项目;在手机上运行,很好;在AVD的模拟器上运行,也很好;
用 chrome 浏览器连接真机想Inspect进行调试,已经看到打开哪些网页l了,但就是Inspect不了,好吧,我的手机是红米,目前是4.2,需要4.4.2才支持;
用 chrome 浏览器连接AVD的虚拟机来Inspect进行调试,同样看到打开哪些网页l了,但就是Inspect不了,好吧,翻墙,给 chrome安装上ADB插件,还是 Inspect不了;
好吧,安装上了一个号称快得多的Genymotion,再下了一个4.4.4的镜像,终于可以用chrome注入进行代码调试了;
但是,谁说额Genymotion速度要快的啊?除了虚拟机启动速度快那么一点意外,
俺的I7、8G内存跑HelloMui无论是启动速度还是响应速度,比起安装上 InterHAXL 再加 Inter ATOM 的虚拟机速度慢的实在太多了;
好吧,俺忍。。。。等 魅蓝Note2 出来俺就换手机;
开始仔细看 index.html 的代码和 List.html 的代码;
好吧,目前为止 , 可以知道 mui.init 里面那个object带的属性有:
swipeBack:true //启用右滑关闭功能
statusBarBackground: '#f7f7f7',
gestureConfig:{
doubletap:true
},
subpages: [{
id: 'list',
url: 'list.html',
styles: {
top: '45px',
bottom: 0,
bounce: 'vertical'
}
},
styles:{ .... }
那么 statusBarBackground 这个参数是干啥的呢?貌似是状态栏的背景颜色,有没有其他类似的其他属性呢?不知道;
甚至, statusBarBackground 这个属性在 MUI自己的API文档里提都没有提到过,是我在 index.html的第27行里面翻出来的;
好吧,继续往下看, mui.os 这个又什么东东?继续翻API,很遗憾,还是没有;
看 HBuilder的提示, mui里面有 ajaxSetting, data, fn, os, gestures, options 。等几个属性,好吧,大家暂时记得 mui.os 里面记录了操作系统的一些环境变量的定义就可以了;至于其他属性,大家就当没有看到吧;
那个弹出菜单因为俺估计用不到,所以嘛,就跳过了;
继续往下看,到了显示关于 页面的处理了;
俺贴出代码吧,
document.getElementById('info').addEventListener('tap', function() {
if (subWebview == null) {
//获取共用父窗体
template = plus.webview.getWebviewById("default-main");
}
if(template){
subWebview = template.children()[0];
subWebview.loadURL('examples/info.html');
//修改共用父模板的标题
mui.fire(template, 'updateHeader', {
title: '关于XXXX',
showMenu: false
});
template.show('slide-in-right', 150);
}
});
plus.webview.getWebviewById("default-main"); 这个 default-main 是啥东东??
开 MUI API文档,没有; 看 H5 Api文档,还是没有;整个项目查找, 稀奇了,还是没有:
好吧,俺承认失败了,姑且认为 default-main 是整个程序第一个加载的页面吧;(这个看法是错误的,稍后会说明);
继续往下看,没有其他需要注意的地方了;真的没有了?
template.children()[0] 这个是啥东东,问题回到原点,归根结底还是需要知道 plus.webview.getWebviewById("default-main") 是什么东东;
暂时放下这个问题, subWebview.loadURL('examples/info.html'); 这个没有疑问;
//修改共用父模板的标题
mui.fire(template, 'updateHeader', {
title: '关于XXXX',
showMenu: false
});
template.show('slide-in-right', 150);
很简单吧?没有这么简单;大家打开 examples/info.html 这个页面,会发现里面也定义了 Header,俺比较偏执,总觉得这儿不应该定义 Header,于是就把 info.html 页面里面的 Header 给注释掉了,呵呵,果然标题照样给改掉了;
说明什么?说明, mui.fire(template, 'updateHeader' 这个修改的不是 info.html 里面 Header 定义的标题;
好吧,打开 关于 页面,再按 Back 按钮,首页标题还是 Hello mui,
说明什么?说明,mui.fire(template, 'updateHeader' 这个修改的不是 index.html 里面 Header 定义的标题;
那么到底修改的是哪儿的Header的内容?
再次打开 关于 页面,可以发现 页面切换时会显示 加载中 这三个字;本来我以为这个是 mui 在页面切换时的自动提示,但还是在整个项目中搜了一下,居然发现在 example/template.html 中有这个三个字,怀着好奇的心情,俺把这三个字改成了 TMD , 结果,呵呵,页面切换时果然显示了 TMD ;
好吧,俺服了;继续找 template.html 在哪儿被引用;
list.html 中有这样的定义: getTemplate('default', 'examples/template.html'); 再看 getTemplate的方法定义,
var headerWebview = mui.preload({
url:header,
id:name "-main",
styles:{
popGesture:"hide",
},
extras:{
mType: 'main'
}
});
终于,俺们找到了 default-main 是在哪儿定义的了;
再看下面的代码,headerWebview.append(subWebview); 终于也找到 template.children()[0] 是啥东东了。。。
说到这儿,大家以为完了?哪有这么简单;
subWebview.loadURL('examples/info.html'); 大家还记得吧,上面我把 info.html 的 Header部分注释掉了,现在俺把 Header 给改回来,
那么 这个 subWebview 加载的页面应该也包含有 一个 Header, 可是这个 info.html 里面的这个 Header 无论如何也不会显示出来?
现在,问题来了,这个 Header 到底到哪儿去了?
暂时就这样了;
经过这个这个分析,俺有些怀疑自己的选择了。。。
收起阅读 »![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/00/06/97_avatar_mid.jpg?v=1645774525)
Appstore提交错误及解决方案
问题1:
解决方案:
进入Apple MemberCenter,去掉appid的Associated Domains,重新生成profile文件重新打包
问题2:
上传app,一直卡在“正在通过 App Store 进行鉴定”
http://ask.dcloud.net.cn/question/6792
问题3:
ERROR ITMS-90085: "No architectures in the binary. Lipo failed to detect any architectures in the bundle executable."
生成的api分析文件太大,我们无法在交付前验证您的api信息
http://ask.dcloud.net.cn/question/10148
问题4
解决方案:
这个是缺少启动图片导致的,请保证配置了启动图和启动图格式正确
问题5
QQ分享 IOS 审核被拒的问题
http://ask.dcloud.net.cn/question/10368
问题6
This bundle is invalid - The Info.plist file for /Payload/DCloud_Pandora.app/Pandora/apps/com.taitaikg.app is missing or could not be read.
Invalid Bundle - The bundle at '/Payload/DCloud_Pandora.app/Pandora/apps/com.taitaikg.app' does not contain a bundle executable.
http://ask.dcloud.net.cn/question/15088
问题7
上传提示
you must define an input diretory
http://ask.dcloud.net.cn/question/5504
问题1:
解决方案:
进入Apple MemberCenter,去掉appid的Associated Domains,重新生成profile文件重新打包
问题2:
上传app,一直卡在“正在通过 App Store 进行鉴定”
http://ask.dcloud.net.cn/question/6792
问题3:
ERROR ITMS-90085: "No architectures in the binary. Lipo failed to detect any architectures in the bundle executable."
生成的api分析文件太大,我们无法在交付前验证您的api信息
http://ask.dcloud.net.cn/question/10148
问题4
解决方案:
这个是缺少启动图片导致的,请保证配置了启动图和启动图格式正确
问题5
QQ分享 IOS 审核被拒的问题
http://ask.dcloud.net.cn/question/10368
问题6
This bundle is invalid - The Info.plist file for /Payload/DCloud_Pandora.app/Pandora/apps/com.taitaikg.app is missing or could not be read.
Invalid Bundle - The bundle at '/Payload/DCloud_Pandora.app/Pandora/apps/com.taitaikg.app' does not contain a bundle executable.
http://ask.dcloud.net.cn/question/15088
问题7
上传提示
you must define an input diretory
http://ask.dcloud.net.cn/question/5504
![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/00/00/46_avatar_mid.jpg?v=0)
Android配置应用主题皮肤
5+ API中提供plus.nativeUI.*提供系统原生类控件的调用,其样式由Android平台提供界面主题决定,新版本(5.9.0)App云端打包默认为“@android:style/Theme.DeviceDefault.Light”(以前版本默认为“@android:style/Theme.DeviceDefault”)。
从5.9.0版本后HBuilder可支持自定义程序主题,打开应用的manifest.json文件,切换到“代码视图”
- 5+ APP
在 "plus" -> "distribute" -> "google" 节点下添加“theme”字段 - uni-app
在 "app-plus" -> "distribute" -> "android" 节点下添加“theme”字段
并配置要使用的应用主题:
值为字符串类型,必须是Android系统支持的类型,注意云端打包编译环境。
- HBuilder
Android4.4(API Level19)SDK - HBuilderX
Android Q (API Level29)SDK
如果输入的类型无效则会提示以下错误:
res/values/dcloud_activity_styles.xml:2: error: Error retrieving parent for item: No resource found that matches the given name 'XXXXXXXXXXXXXXXX'.
推荐使用以下主题样式
- @android:style/Theme.DeviceDefault
系统默认样式(暗色系),通常是黑底白字 - @android:style/Theme.DeviceDefault.Light
系统默认明亮样式(亮色系),通常是白底黑字
Android API19支持的样式列表如下:
配置完成保存提交App云端打包后才能生效
注意!!!更改主题时建议使用NoActionBar系列主题。如果配置其他样式主题可能会导致页面顶部多出一个ActionBar UI(actionBar)
5+ API中提供plus.nativeUI.*提供系统原生类控件的调用,其样式由Android平台提供界面主题决定,新版本(5.9.0)App云端打包默认为“@android:style/Theme.DeviceDefault.Light”(以前版本默认为“@android:style/Theme.DeviceDefault”)。
从5.9.0版本后HBuilder可支持自定义程序主题,打开应用的manifest.json文件,切换到“代码视图”
- 5+ APP
在 "plus" -> "distribute" -> "google" 节点下添加“theme”字段 - uni-app
在 "app-plus" -> "distribute" -> "android" 节点下添加“theme”字段
并配置要使用的应用主题:
值为字符串类型,必须是Android系统支持的类型,注意云端打包编译环境。
- HBuilder
Android4.4(API Level19)SDK - HBuilderX
Android Q (API Level29)SDK
如果输入的类型无效则会提示以下错误:
res/values/dcloud_activity_styles.xml:2: error: Error retrieving parent for item: No resource found that matches the given name 'XXXXXXXXXXXXXXXX'.
推荐使用以下主题样式
- @android:style/Theme.DeviceDefault
系统默认样式(暗色系),通常是黑底白字 - @android:style/Theme.DeviceDefault.Light
系统默认明亮样式(亮色系),通常是白底黑字
Android API19支持的样式列表如下:
配置完成保存提交App云端打包后才能生效
注意!!!更改主题时建议使用NoActionBar系列主题。如果配置其他样式主题可能会导致页面顶部多出一个ActionBar UI(actionBar)
![](http://img-cdn-tc.dcloud.net.cn/uploads/avatar/000/00/00/16_avatar_mid.jpg?v=0)
APICloud产品与DCloud深度对比分析
> 更新:最新版比较详见:https://ask.dcloud.net.cn/article/36732
========以下为历史内容=========
其实就选型对比而言,不深入看产品,有4点就足矣。
- APICloud反编译和抄袭DCloud代码,已经被北京知识产权法院判决,赔偿DCloud损失并向DCloud道歉。详见。
如此不道德的公司存在是给中国的程序员界丢脸。
而支持、纵容侵权产品,让侵权公司得不到应有惩罚,侵权行为屡禁不止,最终劣币驱逐良币,中国无人创新,最终我们用的软件都是外国写的。
这样的环境,是谁营造的?
其实人人有责。
抵制破解、抄袭、侵权,维护正义、维护中国的软件创新环境,人人有责。
2. DCloud的产品有众多一线互联网公司案例
除了众多创业公司,一线互联网公司如360、大众点评、京东、网易、唯品会、新浪、阿里巴巴也纷纷选择DCloud的工具开发app。
以唯品会、有道词典、大众点评为例,体验完全达到一线互联网公司的苛刻要求。(具体看DCloud官网案例)
这是其他跨平台开发工具所没有取得的成绩,在这些案例的过程中大公司们对DCloud的产品反复提要求,最终打磨出别的产品所不具备的功能和性能。
用DCloud的产品肯定可以达到这种效果,不用DCloud,万一没达到效果,客户和老板问起来:明明你知道DCloud可以,为何冒险用别的?好像很难解释。。。
3. 自卖自夸没用,要看三方有公信力的数据
DCloud的mui和facebook的react native,是当前最主流的跨平台开发工具。
下图是常见跨平台开发工具的百度指数对比。
访问index.baidu.com可以自己看。
蓝色是HBuilder,绿色是mui,紫色是apicloud,非常明显的可以看出DCloud的产品体量远超过apicloud,而且一直在良性增长,而apicloud已经做不起来了。
再补充一个数据,HBuilder已经有200万开发者了,和国外主流的开发ide也达到并驾齐驱的体量。可以自行查HBuilder和sublime、vscode的百度指数对比。
4. 免费免费免费
apicloud等其他国内跨平台工具都是收费的,虽然有免费版本,但是他们的目标还是要把开发者引导成他们的收费客户。
但DCloud是纯免费的,自由的技术产品。没有vip付费用户跟你抢资源,没有用到一定深度就让你付费。
DCloud的唯一的商业变现是你做好app后,如果想推广,可以找DCloud帮你发展用户,如果想广告变现,DCloud有广告平台帮你变现。
我们对自己的定位是,帮助开发者成功,成功做出app,成功运营好app。
5. 扩展性、灵活性、开放性
DCloud的5+SDK、开源mui,都使得任何开发者不会被我们的产品功能约束,都可以自己扩展原生能力,自己修改框架源码。
最后,即使你觉得DCloud的产品仍然不顺手,你也应该去使用react native、weex等干净的产品,而不是支持侵权的apicloud。
作恶的公司得不到抵制,反而被纵容,根本就不会反思,也给产业树立了极坏的样板。
维护产业健康、伸张正义,人人有责!
更新:DCloud新出了终极跨平台框架uni-app,无论功能、性能,apicloud相比毫无优势。
不止是产品,uni-app在文档、技术服务、视频、插件生态上也都秒杀对手。
不要再谈论DCloud的社区不活跃、文档不友好、没有视频培训教程、插件不够多了,这些观点都过时了,都反超apicloud的了
> 更新:最新版比较详见:https://ask.dcloud.net.cn/article/36732
========以下为历史内容=========
其实就选型对比而言,不深入看产品,有4点就足矣。
- APICloud反编译和抄袭DCloud代码,已经被北京知识产权法院判决,赔偿DCloud损失并向DCloud道歉。详见。
如此不道德的公司存在是给中国的程序员界丢脸。
而支持、纵容侵权产品,让侵权公司得不到应有惩罚,侵权行为屡禁不止,最终劣币驱逐良币,中国无人创新,最终我们用的软件都是外国写的。
这样的环境,是谁营造的?
其实人人有责。
抵制破解、抄袭、侵权,维护正义、维护中国的软件创新环境,人人有责。
2. DCloud的产品有众多一线互联网公司案例
除了众多创业公司,一线互联网公司如360、大众点评、京东、网易、唯品会、新浪、阿里巴巴也纷纷选择DCloud的工具开发app。
以唯品会、有道词典、大众点评为例,体验完全达到一线互联网公司的苛刻要求。(具体看DCloud官网案例)
这是其他跨平台开发工具所没有取得的成绩,在这些案例的过程中大公司们对DCloud的产品反复提要求,最终打磨出别的产品所不具备的功能和性能。
用DCloud的产品肯定可以达到这种效果,不用DCloud,万一没达到效果,客户和老板问起来:明明你知道DCloud可以,为何冒险用别的?好像很难解释。。。
3. 自卖自夸没用,要看三方有公信力的数据
DCloud的mui和facebook的react native,是当前最主流的跨平台开发工具。
下图是常见跨平台开发工具的百度指数对比。
访问index.baidu.com可以自己看。
蓝色是HBuilder,绿色是mui,紫色是apicloud,非常明显的可以看出DCloud的产品体量远超过apicloud,而且一直在良性增长,而apicloud已经做不起来了。
再补充一个数据,HBuilder已经有200万开发者了,和国外主流的开发ide也达到并驾齐驱的体量。可以自行查HBuilder和sublime、vscode的百度指数对比。
4. 免费免费免费
apicloud等其他国内跨平台工具都是收费的,虽然有免费版本,但是他们的目标还是要把开发者引导成他们的收费客户。
但DCloud是纯免费的,自由的技术产品。没有vip付费用户跟你抢资源,没有用到一定深度就让你付费。
DCloud的唯一的商业变现是你做好app后,如果想推广,可以找DCloud帮你发展用户,如果想广告变现,DCloud有广告平台帮你变现。
我们对自己的定位是,帮助开发者成功,成功做出app,成功运营好app。
5. 扩展性、灵活性、开放性
DCloud的5+SDK、开源mui,都使得任何开发者不会被我们的产品功能约束,都可以自己扩展原生能力,自己修改框架源码。
最后,即使你觉得DCloud的产品仍然不顺手,你也应该去使用react native、weex等干净的产品,而不是支持侵权的apicloud。
作恶的公司得不到抵制,反而被纵容,根本就不会反思,也给产业树立了极坏的样板。
维护产业健康、伸张正义,人人有责!
更新:DCloud新出了终极跨平台框架uni-app,无论功能、性能,apicloud相比毫无优势。
不止是产品,uni-app在文档、技术服务、视频、插件生态上也都秒杀对手。
不要再谈论DCloud的社区不活跃、文档不友好、没有视频培训教程、插件不够多了,这些观点都过时了,都反超apicloud的了