Closed Wscats closed 5 years ago
如果遇到我上面的情况,那就是xcode冲命名或者路径不对,因为我用了xcode-beta版本,所以我重新设置了路径就能正常使用了
百度搜索HBuilder,官网下载安装包,解压,运行HBuilder.exe。注册账号,并登陆
在左边右键,选择新建APP,或者点击中间的新建app
在弹出的窗口,填应用名称,根据需求选择项目位置,以及模板内容,注意名字不要带有@等特殊字符,最后点击完成
创建好之后,选择刚刚创建好的项目,在顶部选择运行,根据你的情况现在运行方式
这是我刚刚选择的模板app展示,功能齐全,基本涵盖安卓常用的底层接口,如摄像头,地图,震动,下载等功能
选择要打包的项目,在顶部选择运行,发布原生APK安装包
在弹出的窗口,选择相应证书,如果参数配置未完成,点击顶部参数配置
上传图标,如果不想逐个逐个图标替换,我们可以点击下方生成并替换
这里的SDK配置选项要填上去才能打包,你可以暂时随机填一些乱串上去,最后就是保证所有提醒红叉的地方都要填满,微信登录,微信支付和微信消息及朋友圈的appid三者要统一,其他在测试时可随意
在弹出的窗口,选择相应证书,如果参数配置未完成,点击顶部参数配置,如果配置完成,点击底部打包
真机调试过程中,如果出现如下错误提醒
安装失败,失败原因:Failure [INSTALL_CANCELED_BY_USER]。
请手动点亮手机屏幕,并重新运行真机调试,注:可能需要在手机上确认安装。
勾选了以下几个选项就可以调试了
之前试过用Vue写的项目,用hbuilder打包APP,在页面第一次加载的时候无法获取cookie,storage等 后来发现原来是一定要plus加载完毕之后才能获取对应的信息,所以如果用了其他框架写的项目不要直接加载对应的JS,可以改成这样
function plusReady() {
var script = document.createElement("script");
script.src = "main-fa9faab1705d2e80a7c5.js";//项目的JS
document.body.appendChild(script);
console.log(plus.storage.getItem("token"))
}
document.addEventListener("plusready", plusReady, false);//等待plus准备就绪在加载
这里的官方文档的支付插件配置的请求DEMO是错误的,注意是用 POST 请求,而非 GET 请求
var channel = null;
// 1. 获取支付通道
function plusReady() {
// 获取支付通道
plus.payment.getChannels(function (channels) {
channel = channels[0];
}, function (e) {
alert("获取支付通道失败:" + e.message);
});
}
document.addEventListener('plusready', plusReady, false);
var ALIPAYSERVER = 'http://demo.dcloud.net.cn/helloh5/payment/alipay.php';
var WXPAYSERVER = 'http://demo.dcloud.net.cn/helloh5/payment/wxpay.php';
// 2. 发起支付请求
function pay(id) {
// 从服务器请求支付订单
var PAYSERVER = '';
if (id == 'alipay') {
PAYSERVER = ALIPAYSERVER;
} else if (id == 'wxpay') {
PAYSERVER = WXPAYSERVER;
} else {
plus.nativeUI.alert("不支持此支付通道!", null, "捐赠");
return;
}
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
switch (xhr.readyState) {
case 4:
if (xhr.status == 200) {
plus.payment.request(channel, xhr.responseText, function (result) {
plus.nativeUI.alert("支付成功!", function () {
back();
});
}, function (error) {
plus.nativeUI.alert("支付失败:" + error.code);
});
} else {
alert("获取订单信息失败!");
}
break;
default:
break;
}
}
xhr.open('POST', PAYSERVER);
//如果是POST请求方式,设置请求首部信息
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send("total=0.01");
}
调用定位可选用这个方法plus.geolocation.getCurrentPosition
location() {
var that = this;
if (window.plus) {
plus.geolocation.getCurrentPosition(
function (p) {
that.latitude = p.coords.latitude;
that.longitude = p.coords.longitude;
},
function (e) {
alert("Geolocation error: " + e.message);
}
);
}
}
当然我们可以把经纬度直接发到后台记录,实现实时跟踪定位
sendLocation() {
var that = this;
axios
.get("http://10.3.136.180:9999/sendPostion", {
params: {
latitude: that.latitude,
longitude: that.longitude
}
})
.then(data => {
console.log(data);
})
.catch(() => {});
}
调用plus.audio.getRecorder()
获取音频对象,可以在成功的回调里面获取录音的地址
mounted() {
this.r = plus.audio.getRecorder();
},
startRecord() {
if (this.r == null) {
alert("Device not ready!");
return;
}
this.r.record({
filename: "_doc/audio/"
},
e => {
console.log(e);
this.path = e;
alert("Audio record success!");
},
e => {
alert("Audio record failed: " + e.message);
}
);
}
可以在上面把获取到的录音地址放进来用plus.audio.createPlayer(this.path)
打开,然后播放音频信息,当然也可以播放其他格式的音频信息
startPlay() {
console.log(this.path);
if (plus.audio == undefined) {
alert("Device not ready!");
}
this.p = plus.audio.createPlayer(this.path);
this.p.play(
function () {
alert("Audio play success!");
},
function (e) {
alert("Audio play error: " + e.message);
}
);
}
暂停播放
stopRecord() {
this.r.stop();
}
前端上传逻辑可以直接使用H5的input
配合FormData
格式
uploadImg() {
var fileNode = document.getElementById("file");
var xmlhttp = new XMLHttpRequest();
//设置回调,当请求的状态发生变化时,就会被调用
xmlhttp.onreadystatechange = function () {
//上传成功,返回的文件名,设置到父节点的背景中
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
console.log(xmlhttp.responseText);
}
};
//构造form数据
var data = new FormData();
console.log(fileNode.files);
data.append("avatar", fileNode.files[0]);
console.log(data);
//设置请求,true:表示异步
xmlhttp.open("post", "http://10.3.136.180:9999/requireImg", true);
//不要缓存
//xmlhttp.setRequestHeader("If-Modified-Since", "0");
//提交请求
xmlhttp.send(data);
//清除掉,否则下一次选择同样的文件就进入不到onchange函数中了
fileNode.value = null;
}
<input @change="uploadImg" type="file" id="file" name="avatar">
后端逻辑,配合 express 和 multer 模块可以获取到传过来的文件
var express = require("express");
var multer = require('multer')
var upload = multer({
dest: 'uploads/'
})
var app = express();
app.post("/requireImg", upload.single('avatar'), (req, res) => {
res.append("Access-Control-Allow-Origin", "*")
res.send({
state: "success"
})
})
app.listen(9999)
uni-app
是一个使用Vue.js
开发跨平台应用的前端框架,开发者编写一套代码,可编译到iOS、Android、H5、小程序
等多个平台。
一个uni-app工程,默认包含如下目录及文件:
┌─components uni-app组件目录
│ └─comp-a.vue 可复用的a组件
├─hybrid 存放本地网页的目录,详见
├─platforms 存放各平台专用页面的目录,详见
├─pages 业务页面文件存放的目录
│ ├─index
│ │ └─index.vue index页面
│ └─list
│ └─list.vue list页面
├─static 存放应用引用静态资源(如图片、视频等)的地方,注意:静态资源只能存放于此
├─main.js Vue初始化入口文件
├─App.vue 应用配置,用来配置App全局样式以及监听 应用生命周期
├─manifest.json 配置应用名称、appid、logo、版本等打包信息
└─pages.json 配置页面路由、导航条、选项卡等页面类信息
可以在App.vue
组件里面引入uni.css
定义好的样式,配合已经写好的组件和模板快速开发
<style>
/* uni.css - 通用组件、模板样式库,可以当作一套ui库应用 */
@import "./common/uni.css";
</style>
函数名 | 说明 |
---|---|
onLaunch | 当uni-app 初始化完成时触发(全局只触发一次) |
onShow | 当 uni-app 启动,或从后台进入前台显示 |
onHide | 当 uni-app 从前台进入后台 浏览器页面切换时候会触发,Mac显示屏切换会触发 |
onUniNViewMessage | 对 nvue 页面发送的数据进行监听,可参考 nvue 向 vue 通讯 |
注意
onPullDownRefresh
生命周期配合enablePullDownRefresh
使用在 js 中定义onPullDownRefresh
处理函数(和onLoad等生命周期函数同级),监听该页面用户下拉刷新事件。需要在pages.json
里,找到的当前页面的 pages 节点,并在 style 选项中开启enablePullDownRefresh
。当处理完数据刷新后,uni.stopPullDownRefresh
可以停止当前页面的下拉刷新。
onPullDownRefresh() {
setTimeout(() => {
uni.stopPullDownRefresh()
}, 1000)
}
触底触发的生命周期
onReachBottom() {
console.log('到底了')
}
配置路由和底部的tabbar
,和小程序是差不多的,注意当我们在page
文件夹新建页面的时候,pages.json
文件的pages
内容会自动添加
{
"pages" : [
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path" : "pages/index/index",
"style" : {
"navigationBarTitleText" : "uni-app"
}
},
{
"path" : "pages/home/home",
"style" : {
"navigationBarTitleText" : "设置页"
}
},
{
"path" : "pages/detail/detail",
"style" : {}
}
],
"globalStyle" : {
"navigationBarTextStyle" : "black",
"navigationBarTitleText" : "uni-app",
"navigationBarBackgroundColor" : "#F8F8F8",
"backgroundColor" : "#F8F8F8"
},
"tabBar" : {
"color" : "#7A7E83",
"selectedColor" : "#007AFF",
"borderStyle" : "black",
"backgroundColor" : "#ffffff",
"list" : [
{
"pagePath" : "pages/index/index",
"iconPath" : "static/component.png",
"selectedIconPath" : "static/componentHL.png",
"text" : "组件"
},
{
"pagePath" : "pages/home/home",
"iconPath" : "static/component.png",
"selectedIconPath" : "static/componentHL.png",
"text" : "组件"
}
]
}
}
声明式导航:用绝对路径或者相对当前组件的相对路径,这里的路由跳转用了绝对路径
<navigator url="/pages/detail/detail" hover-class="navigator-hover"></navigator>
<navigator url="navigate/navigate?title=navigate" hover-class="navigator-hover"></navigator>
编程式导航
// 保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面。
uni.navigateTo({
url: 'test?id=1&name=uniapp'
});
// 关闭当前页面,跳转到应用内的某个页面。
uni.redirectTo({
url: 'test?id=1'
});
// 关闭所有页面,打开到应用内的某个页面。
uni.reLaunch({
url: 'test?id=1'
});
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
uni.switchTab({
url: '/pages/index/index'
});
// 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层
// 此处是A页面
uni.navigateTo({
url: 'B?id=1'
});
// 此处是B页面
uni.navigateTo({
url: 'C?id=1'
});
// 在C页面内 navigateBack,将返回A页面
uni.navigateBack({
delta: 2
});
可以使用uni-app
帮我封装好的组件,但有几个比较注意的是,组件的名字不要用一些微信小程序或者一些常用的名字,我们可以在前面加个后缀,防止无效
<template>
<view>
<xswiper />
<xaudio />
<xmediaList />
<xmap />
</view>
</template>
import xaudio from '../../components/audio/audio.vue'
import xmap from '../../components/map/map.vue'
import xswiper from '../../components/swiper/swiper.vue'
import xmediaList from '../../components/media-list/media-list.vue'
可以使用uni.request
发起请求
const requestUrl = "https://cnodejs.org/api/v1/topics"
const duration = 2000
export default {
data() {
return {
loading: false,
res: ""
}
},
methods: {
makeRequest: function() {
this.loading = true
uni.request({
url: requestUrl,
data: {
noncestr: Date.now()
},
success: (res) => {
uni.showToast({
title: '请求成功',
icon: 'success',
mask: true,
duration: duration
})
this.res = '请求结果 : ' + JSON.stringify(res);
console.log('request success', res)
},
fail: (err) => {
console.log('request fail', err);
uni.showModal({
content: err.errMsg,
showCancel: false
})
},
complete: () => {
this.loading = false
}
})
}
}
}
这里注意要把小程序的单向数据绑定和指令改为vue
的写法,也可以使用uni.createCameraContext()
兼容性会更好
<template>
<view>
<text>text</text>
<camera device-position="back" flash="off" binderror="error" style="width: 100%; height: 300px;"></camera>
<button type="primary" @click="takePhoto">拍照</button>
<view>预览</view>
<image mode="widthFix" :src="src"></image>
</view>
</template>
<script>
export default {
data() {
return {
src:""
};
},
methods: {
takePhoto() {
const ctx = wx.createCameraContext()
ctx.takePhoto({
quality: 'high',
success: (res) => {
this.src = res.tempImagePath
}
})
},
}
}
</script>
必备环境安装
1.配置JDK和Gradle环境
用的是1.8的版本,网上很多地方可以下载,这里不上链接了 在本地配置sdk变量,如图,点击桌面(计算机)->右键属性->高级系统设置->系统属性面板高级->点击环境变量->在下面框中的系统变量中新建
2.下载Android SDK
推荐国内的android-studio下载 然后配置Android SDK环境,ANDROID_HOME定位到你的SDK文件夹的根目录
重启电脑
Cordova安装
1.下载Node.js
node官网
2.在mac终端运行下面命令,输入密码安装cordova
如果是Window系统,去掉sudo
sudo是因为需要管理员权限,-g是全局安装 cordvoa官网命令行帮助
3.执行以下代码创建一个cordvoa应用
第一个参数是文件目录,第二个参数是app id, 第三个参数是显示的title
IOS打包
4.定位到hello目录文件夹,为项目安装平台模块
5.打开xcodeproj项目的文件位置双击打开,如果已安装Xcode就能顺利的打开项目了
hello/platform/ios/
6.可以用编写html项目的IDE打开www下的index.html查看效果,在浏览器打开即可
7.在Xcode打开iOS 模拟器如果看到以下效果说明环境已经搭建成功
ANDROID打包
续前面三步
4.定位到hello目录文件夹,为项目安装平台模块
5.生成APK文件
遇到这个问题就是gradle下载失败了,可以尝试拿图中的链接手动下载然后把它放到对应的系统文件下,如下,注意版本一定要对应上
gradle-2.14.1-all.zip下载地址 或者android-studio下载 成功就会显示如下 apk的目录如下:
6.更改应用桌面图标
在cordova生成项目的跟目录创建res文件夹 然后更改config.xml文件
7.调用相机
安装成功就会在plugin出现两个文件夹
cordova-plugin-camera
和cordova-plugin-compat