东翌学院和Dcloud官方合作跨平台APP开发培训机构
东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,谢谢Dcloud提供这么好的平台!
咨询报名QQ:2971611409 欢迎有意向学习的朋友加好友咨询!
东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,谢谢Dcloud提供这么好的平台!
咨询报名QQ:2971611409 欢迎有意向学习的朋友加好友咨询!
东翌学院和Dcloud官方合作跨平台APP开发培训机构
东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,谢谢Dcloud提供这么好的平台!
咨询报名QQ:3391832203 欢迎有意向学习的朋友加好友咨询! 东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,谢谢Dcloud提供这么好的平台!
咨询报名QQ:3391832203 欢迎有意向学习的朋友加好友咨询! 收起阅读 »
【文档】解决 MUI v3.2.0 headers 为 {'Content-Type': 'application/json'} 发起 POST 请求异常的问题
Mui v3.2.0中ajax设置headers为{'Content-Type': 'application/json'}发起post请求,后端接收不到数据的解决方案(php为例)
问题场景
php部分
<?php
$name = $_POST['name'];
$password = $_POST['password'];
var_dump($name);
var_dump($password);
?>
mui.ajax()部分
mui.ajax({
url: 'http://192.168.12.74:80/test01.php',
type: 'post',
headers:{'Content-Type': 'application/json'},
data: {
name: 'dcloud',
password: '123456'
},
success: function(data) {
console.log(data);
},
error: function(xhr, type, errorThrown) {
console.log(type);
}
});
控制台信息
Notice: Undefined index: name in test01.php on line 2
Notice: Undefined index: password in test01.php on line 3
我们按照通常的post方法去读取数据,发现并没有name和password这两个参数。
问题分析
可以参看下这篇文章《四种常见的 POST 提交数据方式》
当application/json这个Content-Type作为响应头时,我们需要手动处理一下:
从php://input 里获得原始输入流,再json_decode成对象。
方案一
php部分
<?php
if ($_SERVER["CONTENT_TYPE"] == "application/json") {
$input = file_get_contents('php://input');
var_dump($input);
$object = json_decode($input);
$name = $object->name;
var_dump($name);
}
?>
控制台信息一
'name=dcloud&password=123456' test01.php on line 4
null test01.php on line 7
此时,$input并不是一串json字符串,所以我们用json_decode去转换依旧是失败的,并不能拿到我们想要的数据。
mui.ajax()部分
mui.ajax()默认会对data里面的数据进行序列化,最终导致php接受到的是序列化以后的字符串。我们需要禁用对data的序列化(processData:false),并把参数对象序列化成json字符串(JSON.stringify())传给data。
mui.ajax({
url: 'http://192.168.12.74:80/test01.php',
type: 'post',
headers: {
'Content-Type': 'application/json'
},
processData: false,
data: JSON.stringify({
name: 'dcloud',
password: '123456'
}),
success: function(data) {
console.log(data);
},
error: function(xhr, type, errorThrown) {
console.log(type);
}
});
控制台信息二
'dcloud' test01.php on line 7
name参数的值被正确解析,问题解决。
方案二
只需修改php部分即可,方案一中我们在未设置processData属性为false时,获取的是一串序列化后的字符串'name=dcloud&password=123456'。我们对字符串进行截取,同样可以解析出我们想要的参数数据。
php部分
<?php
if($_SERVER["CONTENT_TYPE"]=="application/json"){
$input = file_get_contents('php://input');
$arr = explode("&", $input);
$narr = explode("=", $arr[0]);
$parr = explode("=", $arr[1]);
$name = $narr[1];
$password = $parr[1];
var_dump($name);
var_dump($password);
}
?>
mui.ajax()部分:
mui.ajax({
url: 'http://192.168.12.74:80/test02.php',
type: 'post',
headers: {
'Content-Type': 'application/json'
},
data: {
name: 'dcloud',
password: '123456'
},
success: function(data) {
console.log(data);
},
error: function(xhr, type, errorThrown) {
console.log(type);
}
});
控制台信息
'dcloud' test02.php on line 9
'123456' test02.php on line 10
通过对字符串的截取分组,最终取得我们想要的参数数据,但是此方法的缺点在于参数的顺序不明或数量太多会非常繁琐。
后续解决
Mui v3.3.0,将对此情况进行更加精确的处理,3.2.0版本遇到此问题可按照上面的方式进行处理数据。
Mui v3.2.0中ajax设置headers为{'Content-Type': 'application/json'}发起post请求,后端接收不到数据的解决方案(php为例)
问题场景
php部分
<?php
$name = $_POST['name'];
$password = $_POST['password'];
var_dump($name);
var_dump($password);
?>
mui.ajax()部分
mui.ajax({
url: 'http://192.168.12.74:80/test01.php',
type: 'post',
headers:{'Content-Type': 'application/json'},
data: {
name: 'dcloud',
password: '123456'
},
success: function(data) {
console.log(data);
},
error: function(xhr, type, errorThrown) {
console.log(type);
}
});
控制台信息
Notice: Undefined index: name in test01.php on line 2
Notice: Undefined index: password in test01.php on line 3
我们按照通常的post方法去读取数据,发现并没有name和password这两个参数。
问题分析
可以参看下这篇文章《四种常见的 POST 提交数据方式》
当application/json这个Content-Type作为响应头时,我们需要手动处理一下:
从php://input 里获得原始输入流,再json_decode成对象。
方案一
php部分
<?php
if ($_SERVER["CONTENT_TYPE"] == "application/json") {
$input = file_get_contents('php://input');
var_dump($input);
$object = json_decode($input);
$name = $object->name;
var_dump($name);
}
?>
控制台信息一
'name=dcloud&password=123456' test01.php on line 4
null test01.php on line 7
此时,$input并不是一串json字符串,所以我们用json_decode去转换依旧是失败的,并不能拿到我们想要的数据。
mui.ajax()部分
mui.ajax()默认会对data里面的数据进行序列化,最终导致php接受到的是序列化以后的字符串。我们需要禁用对data的序列化(processData:false),并把参数对象序列化成json字符串(JSON.stringify())传给data。
mui.ajax({
url: 'http://192.168.12.74:80/test01.php',
type: 'post',
headers: {
'Content-Type': 'application/json'
},
processData: false,
data: JSON.stringify({
name: 'dcloud',
password: '123456'
}),
success: function(data) {
console.log(data);
},
error: function(xhr, type, errorThrown) {
console.log(type);
}
});
控制台信息二
'dcloud' test01.php on line 7
name参数的值被正确解析,问题解决。
方案二
只需修改php部分即可,方案一中我们在未设置processData属性为false时,获取的是一串序列化后的字符串'name=dcloud&password=123456'。我们对字符串进行截取,同样可以解析出我们想要的参数数据。
php部分
<?php
if($_SERVER["CONTENT_TYPE"]=="application/json"){
$input = file_get_contents('php://input');
$arr = explode("&", $input);
$narr = explode("=", $arr[0]);
$parr = explode("=", $arr[1]);
$name = $narr[1];
$password = $parr[1];
var_dump($name);
var_dump($password);
}
?>
mui.ajax()部分:
mui.ajax({
url: 'http://192.168.12.74:80/test02.php',
type: 'post',
headers: {
'Content-Type': 'application/json'
},
data: {
name: 'dcloud',
password: '123456'
},
success: function(data) {
console.log(data);
},
error: function(xhr, type, errorThrown) {
console.log(type);
}
});
控制台信息
'dcloud' test02.php on line 9
'123456' test02.php on line 10
通过对字符串的截取分组,最终取得我们想要的参数数据,但是此方法的缺点在于参数的顺序不明或数量太多会非常繁琐。
后续解决
Mui v3.3.0,将对此情况进行更加精确的处理,3.2.0版本遇到此问题可按照上面的方式进行处理数据。
收起阅读 »我是设计,需要设计的找我,价格公道
专业设计,价格公道,态度友好,两年设计经验,需要设计的找我。
扣扣:80883080
专业设计,价格公道,态度友好,两年设计经验,需要设计的找我。
扣扣:80883080
style.less的使用
@width: 200px; //定义一个变量width,里面存储了一个数据100px
@height: 200px;
@color1: rgba(188,166,188,0.8);
@color2: red;
@color3: aqua;
/*
- 变量的作用,可以实现修改一处变幻多处的目的,同时缩小代码维护的范围,
- 提高代码维护的效率,减少代码维护的成本。
/
/ - 混入:将公用的一段代码写入到一个对应的class选择器中,将来使用到该段代码的部分我们可以用
- 该class选择器替换,这个过程叫混入
- 混入分为带参数的混入和不带参数的混入,但是为了提高代码的可复用性,我们一般使用带参数
- 混入,另外参数可以设置默认值,多个参数之间用","隔开。
- 注意:不带参数的混入适用于操作固定的时候,比如过渡效果,如果过渡时间相同时,我们可以使用
/
.transition(@time:1s) {
-webkit-transition: @time;
-moz-transition: @time;
-ms-transition: @time;
-o-transition: @time;
transition: @time;
}
.translate(@distanceX:0, @distanceY:0) {
-webkit-transform: translate(@distanceX,@distanceY);
-moz-transform: translate(@distanceX,@distanceY);
-ms-transform: translate(@distanceX,@distanceY);
-o-transform: translate(@distanceX,@distanceY);
transform: translate(@distanceX,@distanceY);
}
.out {
width: (2@width);
height: (2*@height);
background-color: @color1;
.first {
width: @width;
height: @height;
background-color: @color3;
.transition(2s);
}
.first:hover {
.translate(0,800px);
}
.last {
width: @width;
height: @height;
background-color: @color2;
.transition(5s);
}
.last:hover {
.translate(500px,-300px);
}
}
@width: 200px; //定义一个变量width,里面存储了一个数据100px
@height: 200px;
@color1: rgba(188,166,188,0.8);
@color2: red;
@color3: aqua;
/*
- 变量的作用,可以实现修改一处变幻多处的目的,同时缩小代码维护的范围,
- 提高代码维护的效率,减少代码维护的成本。
/
/ - 混入:将公用的一段代码写入到一个对应的class选择器中,将来使用到该段代码的部分我们可以用
- 该class选择器替换,这个过程叫混入
- 混入分为带参数的混入和不带参数的混入,但是为了提高代码的可复用性,我们一般使用带参数
- 混入,另外参数可以设置默认值,多个参数之间用","隔开。
- 注意:不带参数的混入适用于操作固定的时候,比如过渡效果,如果过渡时间相同时,我们可以使用
/
.transition(@time:1s) {
-webkit-transition: @time;
-moz-transition: @time;
-ms-transition: @time;
-o-transition: @time;
transition: @time;
}
.translate(@distanceX:0, @distanceY:0) {
-webkit-transform: translate(@distanceX,@distanceY);
-moz-transform: translate(@distanceX,@distanceY);
-ms-transform: translate(@distanceX,@distanceY);
-o-transform: translate(@distanceX,@distanceY);
transform: translate(@distanceX,@distanceY);
}
.out {
width: (2@width);
height: (2*@height);
background-color: @color1;
.first {
width: @width;
height: @height;
background-color: @color3;
.transition(2s);
}
.first:hover {
.translate(0,800px);
}
.last {
width: @width;
height: @height;
background-color: @color2;
.transition(5s);
}
.last:hover {
.translate(500px,-300px);
}
}
让 dtpicker 可选择秒钟
让 dtpicker 可选择秒钟
效果图
使用方法
1.引入js
2.type =fulldatetime
<link href="../../css/mui.picker.min.css" rel="stylesheet"/>
<script src="../../js/mui.picker.js"></script>
<link href="../../css/mui.ext.dtpicker.css" rel="stylesheet"/>
<script src="../../js/mui.ext.dtpicker.js"></script>
<span class="mui-badge mui-badge-inverted mui-badge-none mui-custom-date" data-options='{"type":"fulldatetime"}' data-current='false'></span>
下面有附件可以下在 mui.ext.dtpicker.css 及 mui.ext.dtpicker.js
让 dtpicker 可选择秒钟
效果图
使用方法
1.引入js
2.type =fulldatetime
<link href="../../css/mui.picker.min.css" rel="stylesheet"/>
<script src="../../js/mui.picker.js"></script>
<link href="../../css/mui.ext.dtpicker.css" rel="stylesheet"/>
<script src="../../js/mui.ext.dtpicker.js"></script>
<span class="mui-badge mui-badge-inverted mui-badge-none mui-custom-date" data-options='{"type":"fulldatetime"}' data-current='false'></span>
下面有附件可以下在 mui.ext.dtpicker.css 及 mui.ext.dtpicker.js
收起阅读 »东翌学院和Dcloud官方合作跨平台APP开发培训机构
东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 。
咨询报名QQ:3391832203 欢迎有意向学习的朋友加好友咨询! 谢谢Dcloud提供这么好的平台! 东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 。
咨询报名QQ:3391832203 欢迎有意向学习的朋友加好友咨询! 谢谢Dcloud提供这么好的平台! 收起阅读 »
东翌学院和Dcloud官方合作跨平台APP开发培训机构
东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,
HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
咨询报名QQ:2971611409欢迎有意向学习的朋友加好友咨询!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,
今天就晚上vip课程八点就要开班了,没有报名学习的小伙伴们抓紧时间报名学习啦,没有钱报名vip也可以学习的,可以分期0首付 12个月免利息 一个月也就是316. 是vip学员没有开权限的同学联系我给你们开权限!详情咨询QQ :2971611409Tel:17090057793
谢谢Dcloud提供这么好的平台!
东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,
HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
咨询报名QQ:2971611409欢迎有意向学习的朋友加好友咨询!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;
东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验 ,
今天就晚上vip课程八点就要开班了,没有报名学习的小伙伴们抓紧时间报名学习啦,没有钱报名vip也可以学习的,可以分期0首付 12个月免利息 一个月也就是316. 是vip学员没有开权限的同学联系我给你们开权限!详情咨询QQ :2971611409Tel:17090057793
谢谢Dcloud提供这么好的平台!
收起阅读 »东翌学院和Dcloud官方合作跨平台APP开发培训机构
东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,
HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验。
咨询报名QQ:3391832203 欢迎有意向学习的朋友加好友咨询! 谢谢Dcloud提供这么好的平台!
东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,
HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!
东翌学院也成立了外包团队,跨平台APP开发、管理软件定制、手机软件开发、微信开发、网页设计 我们以专业的技术、勇于创新的责任感、真诚的服务态度,赢得了客户的信任与尊重;东翌学院提供的设计解决方案正影响越来越多的客户,并让他们的产品拥有了更加良好的交互方式与用户体验。
咨询报名QQ:3391832203 欢迎有意向学习的朋友加好友咨询! 谢谢Dcloud提供这么好的平台!
【交流分享】从小白的角度谈谈Android集成5+SDK的几种方式的应用场景
背景
前一段时间因为项目需求,需要从Hbuilder中转移到原生层做开发,无奈只是熟悉一些java概念,但几乎没接触过Android开发,所以折腾了好久的离线打包。在你决定看这片文章之前,应该也要做好使劲折腾的心理准备。同时,最好看这篇文章之前对集成5 +sdk要有一些基本的概念,所以最好先看看下面这几篇文章,可能就不用继续看我的这点东西了。
1. 官方文档
- 最新SDK下载地址
- 独立应用方式集成
- Android平台以Widget方式集成HTML5 SDK方法
- Android平台以WebView方式集成HTML5 SDK方法
- Android平台使用AndroidStudio离线打包说明
- Android平台第三方插件开发指导
2.开发者分享文章 - 【交流分享】Android独立应用方式集成HTML5 SDK,Widget方式离线打包,空项目讲解
- 【交流分享】Android集成HTML5 SDK,Runtime方式离线打包,空项目讲解
- Android以Widget方式集成自己的hbuilder项目-----Anroid Studio版
相关集成概念
结合所有的官方文档以及官方SDK中的Hello-Integrate项目。我认为,官方对于离线打包有下面的这几种概念(叫法):
1.WebView集成方式 2. Widget集成方式 3. 独立应用集成方式 4. runtime集成方式 5. webApp集成方式
(截图取自官方文档及运行后的Hello-Integrate项目)
相信我,对于我这种首次接触集成SDK的小白来说,看到这一大堆名词及概念的时候,我是这样的
我猜想这么多的概念(叫法)也许是HB的开发者在开发的过程中遗留的问题,可能是项目组成员变动啊,文档整理人员变动啊巴拉巴拉导致的最终概念没有统一,纯属瞎猜。but……项目需求摆在那里,任务摆在那里,你总要解决对吧,懵逼也得硬着头皮上啊。我们开始折腾吧,先不管上面提到的五种叫法或者概念,直接开搞。
开搞
参照上面的那些文档中的方式,每一种集成弄他至少一遍,折腾的过程中可以查查资料,了解一下安卓原生开发的一些基本概念,比如Activity(关于Activity此处可以参考@AronWOng 分享的文章,简洁的介绍了Activity的意思 Android开机自启应用)。或者熟悉下项目的包结构,哪些文件是干啥的,比如Androidmanifest.xml是个什么鬼。折腾了好长一段时间之后,得出了以下的几个结论,注意此结论中并未指定集成方式的叫法(概念),暂时先直接讲要怎么做:
-
如果你只需要离线打包,比如在无法使用HB的云端打包情况下,那么就使用该篇文章中的方式 集成方式a1, 或者集成方式a2,该模式下,不涉及到自己写原生代码,只要按照官方介绍,将自己HB中的项目集成到eclipse或者Android Studio中打包。换种说法就是,如果你没有任何涉及原生开发的需求,并且需要在eclipse或者Android Studio中打包,就采用该模式。
-
如果你有需求会涉及到原生开发,同时又要集成5 + app。以我的项目需求为例,我需要在PDA上开发5 + app,这款PDA就是个基于Android的手机,但是多了一个硬件:扫描器。我需要在App中监听到PDA上的扫描器相关事件,初始化扫描头,开始扫描,获取扫描结果等,并将扫描结果传入5 + App。由于NJS无法实现(或者可以说我不知道怎么使用NJS实现),这个时候我就要采用下面的文章中的做法 集成方式b1或者 集成方式b2。具体实现思路是,我在5 + App对应的Activity中,用java实现对扫描头的监听,并将扫描结果传入5 + app指定的webView,触发js事件,实现5 +app的监听(关于如何在集成SDK后,从java层获取指定webView并传入参数、触发js方法,参考android webApp集成方式 原生主动调用JS方法,此处感谢@DCloud_SDK_骁骑 和 @杰世 的无私帮助与解答)
-
如果你已经在原生层开发好了了App,但是可能在原生层的某些需求中,比如单个页面需要使用5 + 的能力,这种时候采用下面文章中的做法集成方式c。
-
如果你需要在5 +App或者说5 +App的某个特定的webView中,通过js调用原生层的方法,并将原生层方法的执行结果返回至js。还是以我的项目为例,还是说PDA,我需要在5 App中主动调用扫描头,并将扫描头扫描的结果传回5 +App,触发相关js方法。那么采用下面文章中的的方式集成方式d。
总结
讲到这里,相信大家会对目前官方的提供的几种操作方式有一定的了解,那么,现在用我的理解来套用官方的概念(叫法)
-
离线打包:只要不是在HB中进行云端打包,其他方式我们都可以理解为离线打包,因为你都要涉及到将5 +SDK集成到原生层。即便是最傻瓜式的该方法 集成方式a1,也是相当于把集成的工作给你做好了而已。
-
独立应用集成方式,就是Widget集成方式,就是官方SDK中的Hello-Integrate项目里的webApp集成方式,就是 集成方式b1,就是 集成方式b2
-
WebView集成方式,就是集成方式c,也可以理解为集成方式d,此处参考官方SDK中的Hello-Integrate项目里的WebView集成方式
-
Android平台第三方插件开发指导,就是集成方式d。
最后的话
作为HB的用户已经三个月了,感谢DC提供一款如此好用的工具,衷心希望DC越走越好。同时,该文章参考了论坛中很多其他开发者的总结,在此一并感谢。第一次写,文章格式看起来有点乱,审美比较差导致……最后如果我的总结没有太严重的错误的话,那我觉得官方文档中关于5 +SDK的部分概念说明,是时候改改了,也希望大家指出我的错误
背景
前一段时间因为项目需求,需要从Hbuilder中转移到原生层做开发,无奈只是熟悉一些java概念,但几乎没接触过Android开发,所以折腾了好久的离线打包。在你决定看这片文章之前,应该也要做好使劲折腾的心理准备。同时,最好看这篇文章之前对集成5 +sdk要有一些基本的概念,所以最好先看看下面这几篇文章,可能就不用继续看我的这点东西了。
1. 官方文档
- 最新SDK下载地址
- 独立应用方式集成
- Android平台以Widget方式集成HTML5 SDK方法
- Android平台以WebView方式集成HTML5 SDK方法
- Android平台使用AndroidStudio离线打包说明
- Android平台第三方插件开发指导
2.开发者分享文章 - 【交流分享】Android独立应用方式集成HTML5 SDK,Widget方式离线打包,空项目讲解
- 【交流分享】Android集成HTML5 SDK,Runtime方式离线打包,空项目讲解
- Android以Widget方式集成自己的hbuilder项目-----Anroid Studio版
相关集成概念
结合所有的官方文档以及官方SDK中的Hello-Integrate项目。我认为,官方对于离线打包有下面的这几种概念(叫法):
1.WebView集成方式 2. Widget集成方式 3. 独立应用集成方式 4. runtime集成方式 5. webApp集成方式
(截图取自官方文档及运行后的Hello-Integrate项目)
相信我,对于我这种首次接触集成SDK的小白来说,看到这一大堆名词及概念的时候,我是这样的
我猜想这么多的概念(叫法)也许是HB的开发者在开发的过程中遗留的问题,可能是项目组成员变动啊,文档整理人员变动啊巴拉巴拉导致的最终概念没有统一,纯属瞎猜。but……项目需求摆在那里,任务摆在那里,你总要解决对吧,懵逼也得硬着头皮上啊。我们开始折腾吧,先不管上面提到的五种叫法或者概念,直接开搞。
开搞
参照上面的那些文档中的方式,每一种集成弄他至少一遍,折腾的过程中可以查查资料,了解一下安卓原生开发的一些基本概念,比如Activity(关于Activity此处可以参考@AronWOng 分享的文章,简洁的介绍了Activity的意思 Android开机自启应用)。或者熟悉下项目的包结构,哪些文件是干啥的,比如Androidmanifest.xml是个什么鬼。折腾了好长一段时间之后,得出了以下的几个结论,注意此结论中并未指定集成方式的叫法(概念),暂时先直接讲要怎么做:
-
如果你只需要离线打包,比如在无法使用HB的云端打包情况下,那么就使用该篇文章中的方式 集成方式a1, 或者集成方式a2,该模式下,不涉及到自己写原生代码,只要按照官方介绍,将自己HB中的项目集成到eclipse或者Android Studio中打包。换种说法就是,如果你没有任何涉及原生开发的需求,并且需要在eclipse或者Android Studio中打包,就采用该模式。
-
如果你有需求会涉及到原生开发,同时又要集成5 + app。以我的项目需求为例,我需要在PDA上开发5 + app,这款PDA就是个基于Android的手机,但是多了一个硬件:扫描器。我需要在App中监听到PDA上的扫描器相关事件,初始化扫描头,开始扫描,获取扫描结果等,并将扫描结果传入5 + App。由于NJS无法实现(或者可以说我不知道怎么使用NJS实现),这个时候我就要采用下面的文章中的做法 集成方式b1或者 集成方式b2。具体实现思路是,我在5 + App对应的Activity中,用java实现对扫描头的监听,并将扫描结果传入5 + app指定的webView,触发js事件,实现5 +app的监听(关于如何在集成SDK后,从java层获取指定webView并传入参数、触发js方法,参考android webApp集成方式 原生主动调用JS方法,此处感谢@DCloud_SDK_骁骑 和 @杰世 的无私帮助与解答)
-
如果你已经在原生层开发好了了App,但是可能在原生层的某些需求中,比如单个页面需要使用5 + 的能力,这种时候采用下面文章中的做法集成方式c。
-
如果你需要在5 +App或者说5 +App的某个特定的webView中,通过js调用原生层的方法,并将原生层方法的执行结果返回至js。还是以我的项目为例,还是说PDA,我需要在5 App中主动调用扫描头,并将扫描头扫描的结果传回5 +App,触发相关js方法。那么采用下面文章中的的方式集成方式d。
总结
讲到这里,相信大家会对目前官方的提供的几种操作方式有一定的了解,那么,现在用我的理解来套用官方的概念(叫法)
-
离线打包:只要不是在HB中进行云端打包,其他方式我们都可以理解为离线打包,因为你都要涉及到将5 +SDK集成到原生层。即便是最傻瓜式的该方法 集成方式a1,也是相当于把集成的工作给你做好了而已。
-
独立应用集成方式,就是Widget集成方式,就是官方SDK中的Hello-Integrate项目里的webApp集成方式,就是 集成方式b1,就是 集成方式b2
-
WebView集成方式,就是集成方式c,也可以理解为集成方式d,此处参考官方SDK中的Hello-Integrate项目里的WebView集成方式
-
Android平台第三方插件开发指导,就是集成方式d。
最后的话
作为HB的用户已经三个月了,感谢DC提供一款如此好用的工具,衷心希望DC越走越好。同时,该文章参考了论坛中很多其他开发者的总结,在此一并感谢。第一次写,文章格式看起来有点乱,审美比较差导致……最后如果我的总结没有太严重的错误的话,那我觉得官方文档中关于5 +SDK的部分概念说明,是时候改改了,也希望大家指出我的错误
收起阅读 »图像(头像)选择,截取,压缩,上传的分享
思路:
- 通过拍照或者选择一张照片
- 将照片作为底,一个正方形容器作为边界。通过移动正方形容器获取所需图形的边界。
- 截取图片,并压缩到指定大小。
- 上传到服务器。
具体实现:
-
获取照片资源
1.1 从相册选择function chooseImgFromAlbums() { plus.gallery.pick(function(file) { changeToLocalUrl(file); }, function(err) { console.log(JSON.stringify(err)); }, { filter: 'image', multiple: false }); }1.2 拍照
function chooseImgFromPictures() { var cmr = plus.camera.getCamera(); cmr.captureImage(function(file) { changeToLocalUrl(file); }, function(err) { console.log(JSON.stringify(err)); }, { index: '2', }); }1.3 相册选择和拍照选择返回的路径都是绝对路径,为了让其显示在img里面,我们需要转换为本地路径URL地址。此处打开一张新页面来对图片进行处理
function changeToLocalUrl(path) { plus.io.resolveLocalFileSystemURL(path, function(entry) { openWindow('uploadImg.html?src=' entry.toLocalURL()); }); } -
以一个正方形容器截取图片。
此处,自己写了一些简单的js来做图像截取,这些js修改起来也很方便。
首先,看一下整个页面:
功能很简单:点击放大,缩小可以放大缩小正方形的区域。用手指移动正方形,来改变正方形所包含的内容。
实现的思路:通过监听正方形的touchstart和touchmove事件,改变它的top,left值。实现移动。
具体代码如下:
var Clip = {
size: 12, //这个表示正方形目前的边长,乘上一个基数就是当前的像素值
range: {}, //用来控制正方形left和top的极限值,以免移出边界
topCss: 0, //表示当前的top值
leftCss: 0, //表示当前的left值
touchX: 0, //当前的手指所处的X坐标
touchY: 0, //当前手指的Y坐标
timer: null, //用来做touchmove的函数节流,以免连续触发touchmove事件导致的效率问题
changeBase: function(index) { //这个函数用来改变正方形的边长,一般还需要设置最大边长和最小边长
this.size = index;
$('#clip').css({
height: this.size 'rem',
width: this.size 'rem',
lineHeight: this.size 'rem'
});
this.changeRange(); //边长改变,将引起当前top, left和range的变化,统一调changeRange的方法来修改
},
changeRange: function() { //这个方法用来计算初始top, left以及边界值。其算法收到当前页面布局影响,需要自行修改
this.topCss =($('body').height() - baseSize * extraHeight - baseSize * this.size) / 2 baseSize * headerHeight;
this.leftCss = ($('body').width() - baseSize * this.size) / 2;
this.changeClipStyle(this.leftCss, this.topCss);
//极限值,需控制不超出图片区域
var minTop = ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2 baseSize * headerHeight;
var maxTop = $('body').height() - ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2 -
baseSize * footerHeght - baseSize * this.size;
var minLeft = 0;
var maxLeft = $('body').width() - baseSize * this.size;
this.range = {
minTop: minTop,
maxTop: maxTop,
minLeft: minLeft,
maxLeft: maxLeft
};
},
initEvent: function() { //事件初始化
mui('body').on('tap', '#enlarge', function(e) {
Clip.changeBase(1);
});
mui('body').on('tap', '#reduce', function(e) {
Clip.changeBase(-1);
})
var clip = document.getElementById('clip');
//开始接触的时候,记录当前的手指位置
clip.addEventListener('touchstart', function(event) {
Clip.touchX = event.touches ? event.touches[0].clientX : event.screenX;
Clip.touchY = event.touches ? event.touches[0].clientY : event.screenY;
event.preventDefault();
});
//移动后,记录新的位置,设置新的top和left值
clip.addEventListener('touchmove', function(event) {
//设置20ms的事件
if(Clip.timer != null) { //函数节流
return;
}
Clip.timer = setTimeout(function() {
var x = event.touches ? event.touches[0].clientX : event.screenX;
var y = event.touches ? event.touches[0].clientY : event.screenY;
var disX = x - Clip.touchX;
var disY = y - Clip.touchY;
var nowLeft = Clip.leftCss disX;
var nowTop = Clip.topCss disY;
if(nowLeft < Clip.range.minLeft) {
nowLeft = Clip.range.minLeft;
}
if(nowLeft > Clip.range.maxLeft) {
nowLeft = Clip.range.maxLeft;
}
if(nowTop < Clip.range.minTop) {
nowTop = Clip.range.minTop;
}
if(nowTop > Clip.range.maxTop) {
nowTop = Clip.range.maxTop;
}
Clip.changeClipStyle(nowLeft, nowTop);
Clip.touchX = x;
Clip.touchY = y;
Clip.timer = null;
}, 20);
});
},
//设置新的样式,并改变当前的top和left值
changeClipStyle: function(leftCss, topCss) {
$('#clip').css({
left: leftCss 'px',
top: topCss 'px'
});
Clip.leftCss = leftCss;
Clip.topCss = topCss;
}
}
- 移动到正方形到合适的区域后,点击完成,就将完成截取图片和压缩图片的功能。
主要思路是: 调用plus.zip.compressImage函数来完成截取和压缩
3.1. 首先,需要计算出宽高的百分比和离图片左上角的top和left的百分比。同样根据布局不同,计算方式不同。
//获取width和height的百分比
var widthPix = (Clip.size * baseSize / $('#img').width()).toFixed(2) * 100;
var heightPix = (Clip.size * baseSize / $('#img').height()).toFixed(2) * 100;
//获取左上角位置百分比
var topPix = ((Clip.topCss - Clip.range.minTop) / $('#img').height()).toFixed(2) * 100;
var leftPix = (Clip.leftCss / $('#img').width()).toFixed(2) * 100;
3.2 截取
//对图片进行裁剪
plus.zip.compressImage(
{
src: search.src, //src在这里是第一步Url里的src。也就是本地路径
dst: '_doc/a.jpg',
overwrite: true,
clip: {
top: topPix '%',
left: leftPix '%',
width: widthPix '%',
height: heightPix '%'
}
},
function(e) {
resizeImage(e.target); //压缩图片
}
);
3.3 截取图片之后,我们还需要进行压缩。
//再对图片进行压缩为270*270,再上传到服务器
function resizeImage(src) {
plus.zip.compressImage(
{
src: src,
dst: '_doc/a.jpg',
overwrite: true,
width: '270px', //这里指定了宽度,同样可以修改
format: 'jpg',
quality: 100 //图片质量不再修改,以免失真
},
function(e) {
plus.nativeUI.closeWaiting();
uploadImg(e.target); //上传图片, e.target存的是本地路径!
},
function(err) {
plus.nativeUI.alert('未知错误!',function() {
mui.back();
});
}
);
}
-
上传图片到服务器。上传图片用的是plus.uploader,数据格式符合Multipart/form-data规范,也就是平时input type='file'那样一样
function uploadImg(src) { var task = plus.uploader.createUpload(ajaxUrl, { method: 'post', blocksize:204800, timeout: 10 }); task.addFile(src, {key: 'headImg'}); task.addData('type', 'uploadImg'); task.addData('userId', ); task.addEventListener('statechanged', stateChanged, false); task.start(); function stateChanged(upload, status) { if ( upload.state == 4 && status == 200 ) { plus.uploader.clear(); //清除上传 console.log(upload.responseText); //服务器返回存在这里 } } }好了,就这么多,代码比较简单,如果有其他能用的,欢迎修改。源码就不上传了,因为是公司项目的一个子功能,主要代码实现都在这里了。直接用了jQuery和mui。当然用原生写也OK。
思路:
- 通过拍照或者选择一张照片
- 将照片作为底,一个正方形容器作为边界。通过移动正方形容器获取所需图形的边界。
- 截取图片,并压缩到指定大小。
- 上传到服务器。
具体实现:
-
获取照片资源
1.1 从相册选择function chooseImgFromAlbums() { plus.gallery.pick(function(file) { changeToLocalUrl(file); }, function(err) { console.log(JSON.stringify(err)); }, { filter: 'image', multiple: false }); }1.2 拍照
function chooseImgFromPictures() { var cmr = plus.camera.getCamera(); cmr.captureImage(function(file) { changeToLocalUrl(file); }, function(err) { console.log(JSON.stringify(err)); }, { index: '2', }); }1.3 相册选择和拍照选择返回的路径都是绝对路径,为了让其显示在img里面,我们需要转换为本地路径URL地址。此处打开一张新页面来对图片进行处理
function changeToLocalUrl(path) { plus.io.resolveLocalFileSystemURL(path, function(entry) { openWindow('uploadImg.html?src=' entry.toLocalURL()); }); } -
以一个正方形容器截取图片。
此处,自己写了一些简单的js来做图像截取,这些js修改起来也很方便。
首先,看一下整个页面:
功能很简单:点击放大,缩小可以放大缩小正方形的区域。用手指移动正方形,来改变正方形所包含的内容。
实现的思路:通过监听正方形的touchstart和touchmove事件,改变它的top,left值。实现移动。
具体代码如下:
var Clip = {
size: 12, //这个表示正方形目前的边长,乘上一个基数就是当前的像素值
range: {}, //用来控制正方形left和top的极限值,以免移出边界
topCss: 0, //表示当前的top值
leftCss: 0, //表示当前的left值
touchX: 0, //当前的手指所处的X坐标
touchY: 0, //当前手指的Y坐标
timer: null, //用来做touchmove的函数节流,以免连续触发touchmove事件导致的效率问题
changeBase: function(index) { //这个函数用来改变正方形的边长,一般还需要设置最大边长和最小边长
this.size = index;
$('#clip').css({
height: this.size 'rem',
width: this.size 'rem',
lineHeight: this.size 'rem'
});
this.changeRange(); //边长改变,将引起当前top, left和range的变化,统一调changeRange的方法来修改
},
changeRange: function() { //这个方法用来计算初始top, left以及边界值。其算法收到当前页面布局影响,需要自行修改
this.topCss =($('body').height() - baseSize * extraHeight - baseSize * this.size) / 2 baseSize * headerHeight;
this.leftCss = ($('body').width() - baseSize * this.size) / 2;
this.changeClipStyle(this.leftCss, this.topCss);
//极限值,需控制不超出图片区域
var minTop = ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2 baseSize * headerHeight;
var maxTop = $('body').height() - ($('body').height() - baseSize * extraHeight - $('#img').height()) / 2 -
baseSize * footerHeght - baseSize * this.size;
var minLeft = 0;
var maxLeft = $('body').width() - baseSize * this.size;
this.range = {
minTop: minTop,
maxTop: maxTop,
minLeft: minLeft,
maxLeft: maxLeft
};
},
initEvent: function() { //事件初始化
mui('body').on('tap', '#enlarge', function(e) {
Clip.changeBase(1);
});
mui('body').on('tap', '#reduce', function(e) {
Clip.changeBase(-1);
})
var clip = document.getElementById('clip');
//开始接触的时候,记录当前的手指位置
clip.addEventListener('touchstart', function(event) {
Clip.touchX = event.touches ? event.touches[0].clientX : event.screenX;
Clip.touchY = event.touches ? event.touches[0].clientY : event.screenY;
event.preventDefault();
});
//移动后,记录新的位置,设置新的top和left值
clip.addEventListener('touchmove', function(event) {
//设置20ms的事件
if(Clip.timer != null) { //函数节流
return;
}
Clip.timer = setTimeout(function() {
var x = event.touches ? event.touches[0].clientX : event.screenX;
var y = event.touches ? event.touches[0].clientY : event.screenY;
var disX = x - Clip.touchX;
var disY = y - Clip.touchY;
var nowLeft = Clip.leftCss disX;
var nowTop = Clip.topCss disY;
if(nowLeft < Clip.range.minLeft) {
nowLeft = Clip.range.minLeft;
}
if(nowLeft > Clip.range.maxLeft) {
nowLeft = Clip.range.maxLeft;
}
if(nowTop < Clip.range.minTop) {
nowTop = Clip.range.minTop;
}
if(nowTop > Clip.range.maxTop) {
nowTop = Clip.range.maxTop;
}
Clip.changeClipStyle(nowLeft, nowTop);
Clip.touchX = x;
Clip.touchY = y;
Clip.timer = null;
}, 20);
});
},
//设置新的样式,并改变当前的top和left值
changeClipStyle: function(leftCss, topCss) {
$('#clip').css({
left: leftCss 'px',
top: topCss 'px'
});
Clip.leftCss = leftCss;
Clip.topCss = topCss;
}
}
- 移动到正方形到合适的区域后,点击完成,就将完成截取图片和压缩图片的功能。
主要思路是: 调用plus.zip.compressImage函数来完成截取和压缩
3.1. 首先,需要计算出宽高的百分比和离图片左上角的top和left的百分比。同样根据布局不同,计算方式不同。
//获取width和height的百分比
var widthPix = (Clip.size * baseSize / $('#img').width()).toFixed(2) * 100;
var heightPix = (Clip.size * baseSize / $('#img').height()).toFixed(2) * 100;
//获取左上角位置百分比
var topPix = ((Clip.topCss - Clip.range.minTop) / $('#img').height()).toFixed(2) * 100;
var leftPix = (Clip.leftCss / $('#img').width()).toFixed(2) * 100;
3.2 截取
//对图片进行裁剪
plus.zip.compressImage(
{
src: search.src, //src在这里是第一步Url里的src。也就是本地路径
dst: '_doc/a.jpg',
overwrite: true,
clip: {
top: topPix '%',
left: leftPix '%',
width: widthPix '%',
height: heightPix '%'
}
},
function(e) {
resizeImage(e.target); //压缩图片
}
);
3.3 截取图片之后,我们还需要进行压缩。
//再对图片进行压缩为270*270,再上传到服务器
function resizeImage(src) {
plus.zip.compressImage(
{
src: src,
dst: '_doc/a.jpg',
overwrite: true,
width: '270px', //这里指定了宽度,同样可以修改
format: 'jpg',
quality: 100 //图片质量不再修改,以免失真
},
function(e) {
plus.nativeUI.closeWaiting();
uploadImg(e.target); //上传图片, e.target存的是本地路径!
},
function(err) {
plus.nativeUI.alert('未知错误!',function() {
mui.back();
});
}
);
}
-
上传图片到服务器。上传图片用的是plus.uploader,数据格式符合Multipart/form-data规范,也就是平时input type='file'那样一样
function uploadImg(src) { var task = plus.uploader.createUpload(ajaxUrl, { method: 'post', blocksize:204800, timeout: 10 }); task.addFile(src, {key: 'headImg'}); task.addData('type', 'uploadImg'); task.addData('userId', ); task.addEventListener('statechanged', stateChanged, false); task.start(); function stateChanged(upload, status) { if ( upload.state == 4 && status == 200 ) { plus.uploader.clear(); //清除上传 console.log(upload.responseText); //服务器返回存在这里 } } }好了,就这么多,代码比较简单,如果有其他能用的,欢迎修改。源码就不上传了,因为是公司项目的一个子功能,主要代码实现都在这里了。直接用了jQuery和mui。当然用原生写也OK。








