33 uniapp-android+小程序+支付宝上线

33 android+小程序+支付宝上线

一 微信小程序端

0 小程序端配置

Hbuilder配置

image-20200521205258059

微信开发者工具配置

image-20200521205355545

image-20200521205424419

1 处理导航条

app-plus的导航条只有app端可以用,也就意味着其他小程序端需要自定义导航条

使用uni提供的导航条组件需要注意:

ps: 下面的这一堆代码里只需要把uni-status-bar屏蔽掉,小程序端无需给状态栏占位。

<!-- #ifdef APP-PLUS -->
			<uni-status-bar v-if="statusBar" />
<!-- #endif -->
<template>

	<view class="uni-navbar">
		<view :class="{'uni-navbar--fixed': fixed,'uni-navbar--shadow':border,'uni-navbar--border':border}" :style="{'background-color':backgroundColor}" class="uni-navbar__content">
			<!-- #ifdef APP-PLUS -->
			<uni-status-bar v-if="statusBar" />
			<!-- #endif -->
			<view :style="{color:color}" class="uni-navbar__header uni-navbar__content_view">
				<view class="uni-navbar__header-btns uni-navbar__content_view" @tap="onClickLeft">
					<view v-if="leftIcon.length" class="uni-navbar__content_view">
						<uni-icons :type="leftIcon" :color="color" size="24" />
					</view>
					<view v-if="leftText.length" :class="{'uni-navbar-btn-icon-left':!leftIcon.length}" class="uni-navbar-btn-text uni-navbar__content_view">{{ leftText }}</view>
					<slot name="left" />
				</view>
				<view class="uni-navbar__header-container uni-navbar__content_view">
					<view v-if="title.length" class="uni-navbar__header-container-inner uni-navbar__content_view">{{ title }}</view>
					<!-- 标题插槽 -->
					<slot />
				</view>
				<view :class="title.length?'uni-navbar__header-btns-right':''" class="uni-navbar__header-btns uni-navbar__content_view" @tap="onClickRight">
					<view v-if="rightIcon.length" class="uni-navbar__content_view">
						<uni-icons :type="rightIcon" :color="color" size="24" />
					</view>
					<!-- 优先显示图标 -->
					<view v-if="rightText.length&&!rightIcon.length" class="uni-navbar-btn-text uni-navbar__content_view">{{ rightText }}</view>
					<slot name="right" />
				</view>
			</view>
		</view>
		<view v-if="fixed" class="uni-navbar__placeholder">
			
			<!-- #ifdef APP-PLUS -->
			<uni-status-bar v-if="statusBar" />
			<!-- #endif -->
			
			<view class="uni-navbar__placeholder-view" />
		</view>
	</view>
</template>

<script>
	import uniStatusBar from '../uni-status-bar/uni-status-bar.vue'
	import uniIcons from '../uni-icons/uni-icons.vue'

	export default {
		name: 'UniNavBar',
		components: {
			uniStatusBar,
			uniIcons
		},
		props: {
			title: {
				type: String,
				default: ''
			},
			leftText: {
				type: String,
				default: ''
			},
			rightText: {
				type: String,
				default: ''
			},
			leftIcon: {
				type: String,
				default: ''
			},
			rightIcon: {
				type: String,
				default: ''
			},
			fixed: {
				type: [Boolean, String],
				default: false
			},
			color: {
				type: String,
				default: '#000000'
			},
			backgroundColor: {
				type: String,
				default: '#FFFFFF'
			},
			statusBar: {
				type: [Boolean, String],
				default: false
			},
			shadow: {
				type: [String, Boolean],
				default: true
			},
			border: {
				type: [String, Boolean],
				default: true
			}
		},
		methods: {
			onClickLeft() {
				this.$emit('click-left')
			},
			onClickRight() {
				this.$emit('click-right')
			}
		}
	}
</script>

<style>
	@charset "UTF-8";

	.uni-navbar__content {
		display: block;
		position: relative;
		width: 100%;
		background-color: #fff;
		overflow: hidden
	}

	.uni-navbar__content .uni-navbar__content_view {
		display: flex;
		align-items: center
	}

	.uni-navbar__header {
		display: flex;
		flex-direction: row;
		width: 100%;
		height: 44px;
		line-height: 44px;
		font-size: 16px
	}

	.uni-navbar__header-btns {
		display: inline-flex;
		flex-wrap: nowrap;
		flex-shrink: 0;
		width: 120upx;
		padding: 0 12upx
	}

	.uni-navbar__header-btns:first-child {
		padding-left: 0
	}

	.uni-navbar__header-btns:last-child {
		width: 60upx
	}

	.uni-navbar__header-btns-right:last-child {
		width: 120rpx;
		text-align: right;
		flex-direction: row-reverse
	}

	.uni-navbar__header-container {
		width: 100%;
		margin: 0 10upx
	}

	.uni-navbar__header-container-inner {
		width: 100%;
		display: flex;
		justify-content: center;
		font-size: 30upx
	}

	.uni-navbar__placeholder-view {
		height: 44px
	}

	.uni-navbar--fixed {
		position: fixed;
		z-index: 998
	}

	.uni-navbar--shadow {
		box-shadow: 0 1px 6px #ccc
	}

	.uni-navbar--border:after {
		position: absolute;
		z-index: 3;
		bottom: 0;
		left: 0;
		right: 0;
		height: 1px;
		content: '';
		-webkit-transform: scaleY(.5);
		transform: scaleY(.5);
		background-color: #e5e5e5
	}
</style>

以首页为例子,为各类小程序专门设置导航条

只关注 这类

<template>
	<view>
		
		<!-- #ifdef MP -->	
			<uni-nav-bar :shadow="false" :border="false"
			@click-left="clickLeft" @click-right="clickRight">
				<!-- 左边图标 -->
				<block slot="left">
					<view class="iconfont icon-qiandao ml-2 mr-2" style="font-size: 22px;color: #FF9619;"></view>
				</block>
				<!-- 中间搜索框 -->
				<view class="flex justify-center align-center rounded text-muted bg-light flex-1 mt-1" style="margin-left: -46upx;height: 60upx;" @tap="openSearch">
					<view class="iconfont icon-sousuo mr-1"></view>搜索帖子
				</view>
				<!-- 右边图标 -->
				<block slot="right">
					<view class="icon iconfont icon-bianji1 text-dark" style="font-size: 22px;"></view>
				</block>
			</uni-nav-bar>
		<!-- #endif -->
		
		<!-- 顶部选项卡 -->
		<scroll-view scroll-x="true" :scroll-into-view="scrollIndex" scroll-with-animation
		class="scroll-row"
		style="height: 100rpx;">
			<view v-for="(item,index) in tabBars" 
			:key="index" 
			:id="'tab'+index"
			class="scroll-row-item px-2 py-2 font-md"
			:class="tabIndex === index? 'text-main font-lg font-weight-bold':''"
			@click="changeTab(index)">
				{{item.classname}}
			</view>
		</scroll-view>
		
		<!-- 定制选项卡对应的内容 -->
		<!-- current	聚焦在当前子滑块实例的 index 默认会从0 1 2 3。。。依次排列 -->	
		<swiper :duration="150" :current="tabIndex" @change="onChangeTab"
		:style="'height:'+scrollH+'px'">
		<!-- 会默认分配索引 0 1 2 3 4 5  -->
			<swiper-item v-for="(item,index) in newsList" :key="index">
				{{item.name}}
				<scroll-view scroll-y="true" :style="'height:'+scrollH+'px;'" @scrolltolower="loadmore(index)">
					<template v-if="item.list.length>0">
						<!-- 列表 -->
						<block v-for="(item2,index2) in item.list" :key="index2">
							<!-- 列表样式 -->
							<common-list :item="item2" :index="index2" @follow="follow" @doSupport="doSupport"></common-list>
							<!-- 全局分割线 -->
							<divider></divider>
						</block>
						<!-- 上拉加载 -->
						<load-more :loadmore="item.loadmore"></load-more>
					</template>
					
					<!-- 首次加载触发 -->
					<template v-else-if="item.firstLoad">
						<view class="text-light-muted flex align-center justify-center font-md" style="height: 200rpx;">加载中...</view>
					</template>
					
					<!-- 非首次加载没有数据触发 -->
					<template v-else>
						<!-- 无数据渲染页面 -->
						<no-thing>来了啊老弟</no-thing>
						
					</template>	
				</scroll-view>
				
			</swiper-item>
			
		</swiper>
	</view>
</template>

<script>
	// #ifdef MP
	import uniNavBar from '@/components/uni-ui/uni-nav-bar/uni-nav-bar.vue';
	// #endif
	import commonList from '@/components/common/common-list.vue';
	import loadMore from '@/components/common/load-more.vue';
	export default {
		components: {
			commonList,
			loadMore,
			// #ifdef APP-PLUS
			uniNavBar
			// #endif
			
		},
		data() {
			return {
				scrollIndex:"",
				tabIndex: 0,
				tabBars: [],
				newsList: [],
				scrollH:0
				
				
		}
		},
		
		//监听原生标题栏按钮点击事件,参数为Object
		onNavigationBarSearchInputClicked(){
			uni.navigateTo({
				url:'../search/search?type?post',
			})
			
		},
		// 监听导航按钮点击事件
		onNavigationBarButtonTap() {
			this.navigateTo({
				url: '../add-input/add-input',
			})
		},
		onLoad() {
			uni.getSystemInfo({
				success:res=>{
								// 可用窗口高度(屏幕高度-导航栏高度-底部栏高度。) -  选项卡高度
					this.scrollH = res.windowHeight- uni.upx2px(100)
					console.log(this.scrollH)
				}
			})
			// 根据选项生成列表
			this.getData()
			
			// 监听点踩操作进行数据更新。
			uni.$on('updateFollowOrSupport' ,this.listionFollowOrSupport)
			// 监听评论数进行数据更新。
			uni.$on('updateCommentsCount' ,this.updateCommentsCountBack)
			// 监听刷新首页
			uni.$on('updateIndex',this.getData)
			
		},
		onUnload() {
			uni.$off('updateFollowOrSupport',this.listionFollowOrSupport)
			uni.$off('updateCommentsCount',this.updateCommentsCountBack)
			uni.$off('updateIndex',this.getData)
		},
		methods: {
			// #ifdef MP
			clickLeft(){
				console.log('左边事件')
			},
			clickRight(){
				// 打开发布页面
				this.navigateTo({
					url: '../add-input/add-input',
				})
			},
			// #endif
			openSearch(){
				uni.navigateTo({
					url: '../search/search',
				});
			},

			
			// 封装成回掉得意移除页面的时候停止监听
			listionFollowOrSupport(e){
				console.log('index.vue 接受到了')
				switch (e.type){
					case 'follow': // 关注
					this.follow(e.data.user_id)
						break;
					case 'support':
					this.doSupport(e.data)
					default:
						break
				}
			},
			// 监听评论数进行更新
			updateCommentsCountBack(e){
				// console.log('updateCommentsCountBack监听到了')
				this.newsList.forEach(tab=>{
					tab.list.forEach(item=>{
						if (item.id === e.id){
							item.comment_count = e.count
						}
					})
				})
				
			},
			
			// 上拉加载更多
			loadmore(index){
				// 拿到当前列表
				let item = this.newsList[index]
				// 修改当前加载状态
				item.loadmore = '加载中。。。'
				// 分页量+1
				item.page++
				// 模拟数据请求
				this.getList()
				// setTimeout(()=>{
				// 	// 加载数据
				// 				// ... 相当于取出来当前对象可以遍历出来的内容放到了当前对象里面。
				// 				// 这个可以粗糙的理解为把合并了两个一摸一样的列表,列表里面原来的内容*2了 
				// 	item.list = [...item.list,...item.list]
				// 	item.loadmore = '上拉加载更多'
				// },2000)
			},
			
			
			// 制作列表+上拉加载数据初始值
			getData(){
				
				// 获取文章分类,请求用then嵌套写,不然两个请求数据是分先后的。
				this.$H.get('/postclass').then(res=>{
					// let [err,result] = res
					// console.log(result)
					this.tabBars = res.list
					// console.log(this.tabBars)
					// 根据分类生成列表
					var arr = []
					for (let i=0; i < this.tabBars.length; i++){
						arr.push({
							loadmore:"上拉加载更多",
							list:[],
							page:1,
							firstLoad:true
						})
					}
					this.newsList = arr
					
					// 获取第一个分类的数据
					this.getList()
					
				})
				
			},
			
			
			// 获取指定分类下的数据
			getList(){
				if (this.tabBars.length) {
					let index = this.tabIndex // 这步骤很有意义,如果不这么写网络io拉的事件长的情况会使得数据乱掉。
					let id = this.tabBars[index].id
					let page = this.newsList[index].page
					// console.log(page)
					let isrefresh = page === 1   // 第一页的时候涉及到更改,剩下的页根本不涉及到更改。
					this.$H.get('/postclass/'+id+'/post/'+page,{},{
						token:true,
						noExToken:true
						
					})
					.then(res2 => {
						// console.log(res2)
						// console.log(res2.length)
						let list = res2.list.map(v => {
							// 有大括号就是回掉函数,回掉函数的返回值会作为处理后的value
							// console.log(v.titlepic)
							return this.$U.formatCommonList(v)
						})
						// console.log(isrefresh)
						this.newsList[index].list = isrefresh ? list : [...this.newsList[index].list,...list];
						
						
						this.newsList[index].loadmore = list.length<10 ? '没有更多了' : '上拉加载更多';
						
						// 已经获取过一次了,就把首次请求设置为false,并且第二页的时候就不会校验这个了 完美。
						if (isrefresh) {
							this.newsList[index].firstLoad = false
						}
					})
				}
			},
			
			follow(user_id){
				// this.newsList[this.tabIndex].list[e].isFollow = true
				// uni.showToast({title:'关注成功'})
				// console.log(this.newsList)
				this.newsList.forEach(tab=>{
					tab.list.forEach(item=>{
						if (item.user_id === user_id){
							item.isFollow = true
						}
					})
				})
			},
			
			// 切换选项
			changeTab(index){
				if (this.tabIndex === index){
					return;
				}
				this.tabIndex = index
				// 视角滚动到指定元素
				this.scrollIndex = 'tab'+index
				
				// 获取当前分类下的列表数据
				if(this.newsList[this.tabIndex].firstLoad){
					this.getList()
				}	
			},
			
			
			// 监听选项内容滑动
			onChangeTab(e){
				this.changeTab(e.detail.current)
			},
			
			
			// 顶踩操作
			doSupport(e){
				// 拿到当前队对象
				this.newsList[this.tabIndex].list.forEach(item=>{
					// console.log(e)
					// 除非item拿到的是简单类型或手动深拷贝,否则皆为浅拷贝
					// 第一层深拷贝可以考虑做一个{},往里面添加值的形式做到第一层深拷贝
					if (item.id === e.id){
						// console.log('处理前',this.newsList[this.tabIndex].list)
						if (item.support.type === ''){
							item.support[e.type+'_count']++
						} else if (item.support.type === 'support' && e.type === 'unsupport'){
							// 顶 -1
							item.support.support_count--;
							// 踩 +1
							item.support.unsupport_count++;
						} else if (item.support.type === 'unsupport' && e.type === 'support'){
							// 踩 -1
							item.support.unsupport_count --;
							// 顶 +1
							item.support.support_count ++;
						}
						item.support.type = e.type
						// console.log('处理后说明是浅拷贝,影响原来的列表,vue搜集到了直接渲染',this.newsList[this.tabIndex].list)
					}
				})
				let msg = e.type === 'support' ? '顶' : '踩'
				
				uni.showToast({
					title:msg+'成功'
				})
				
				
			}
		}
	}
</script>

<style>

</style>


<!--  -->

	




2 小程序分享

uni官方文档:https://uniapp.dcloud.io/api/plugins/share?id=onshareappmessage

// #ifndef APP-PLUS
		// 微信小程序分享,暂时知道有这么个接口就行了,暂时先不测试
		// ps:如果没写这个,微信小程序会提示当前页面没有设置分享。
		// 和onLoad同级别。
		onShareAppMessage(res) {
			console.log(res)
			return {
			  title: this.info.title,
			  path: '/pages/detail/detail?detail='+JSON.stringify(this.info)
			}
		 },
// #endif

3 小程序登录

ps:源代码后台返回token稍微有点问题,前台业务逻辑没问题。

概念

// 如果简单获取用户信息使用 button微信内置的事件就够了
// 如果想要走后台必然绕不开openid,这个时候就需要uni.login获取code吗再通过我们的服务器获取openid进行数据存储然后再返回给小程序端token保持登录状态。

精华代码

<!-- #ifdef MP-WEIXIN -->
			<button type="primary" open-type="getUserInfo" @getuserinfo="mpGetUserInfo">微信登录</button>
<!-- #endif -->
      
      
// #ifdef MP-WEIXIN
			// 如果简单获取用户信息使用 button微信内置的事件就够了
			// 如果想要走后台必然绕不开openid,这个时候就需要uni.login获取code吗再通过我们的服务器获取openid进行数据存储了。
			mpGetUserInfo(result){
				console.log(result) // res是拿不到唯一标识的
				// console.log(result.detail.userInfo.nickName)
				// console.log(result.detail.userInfo.gender)
				// console.log(result.detail.userInfo.avatarUrl)
				// 需要调用login方法拿到code然后请求后端,后端发送给服务器appid+screetkey,这个时候服务器才会
				// 给我返回openid
				uni.showLoading({ title: '登录中...', mask: true });
				// 获取失败
				if (result.detail.errMsg !== 'getUserInfo:ok') {
					uni.hideLoading();
					uni.showModal({
						title: '获取用户信息失败',
						content: '错误原因' + result.detail.errMsg,
						showCancel: false
					});
					return;
				}
				let userinfo = result.detail.userInfo;
				uni.login({
				  provider: 'weixin',
				  success:  (res)=>{
				    // console.log(res);
					// {code: "071vxLuZ0vxS8V17f7vZ03gLuZ0vxLuo"
					// errMsg: "login:ok"}
					this.MpLogin({
						url:"/wxlogin",
						code:res.code,
						nickName:userinfo.nickName,
						avatarUrl:userinfo.avatarUrl
					})
				  },
				 complete: () => {
				  	uni.hideLoading();
				  }
				});
			},
			// #endif
			
			// #ifdef MP-WEIXIN
			// 后端拿到了code,nickname,avatarurl
			// 后端拿着code换取openid,得到了唯一标示,
			// 然后后端把nickname和avatarurl和openid进行存储。
			MpLogin(options){
				this.$H.post(options.url,{
					code:options.code,
					nickName:options.nickName,
					avatarUrl:options.avatarUrl
				}).then(data=>{
					// console.log(data) // data是空的但是代码流程没啥问题。
					// 修改vuex的state,持久化存储
					this.$store.commit('login',this.$U.formatUserinfo(data))
					// 返回上一页
					if(this.back){
						uni.navigateBack({
							delta: 1
						});
					}
					uni.showToast({
						title: '登录成功',
						icon: 'none'
					});
				}).catch(err=>{
					console.log(err)
				});
			},
			// #endif

设计的outer-login详细代码

<template>
	<view>
		<view class="flex align-center justify-between" style="padding:20rpx 100rpx">
			<!-- #ifdef APP-PLUS || MP-ALIPAY-->
			<view
			v-for="(item,index) in providerList" :key="index"
			class="iconfont text-white font-lgger rounded-circle flex align-center justify-center" 
			style="height:100rpx;width:100rpx;"
			:class="item.icon+' '+item.bgColor"
			@click="login(item)"> 
			<!-- 如果直接写了函数就会直接调用 :login="login(item)"-->
			<!-- 完善login函数 实现第三方登录。 -->  
				
			</view>
			<!-- #endif -->
			
			<!-- #ifdef MP-WEIXIN -->
			<button type="primary" open-type="getUserInfo" @getuserinfo="mpGetUserInfo">微信登录</button>
			<!-- #endif -->
			
		</view>
	</view>
</template>

<script>
	export default {
		props:{
			back:{
				type:Boolean,
				default:false
				
			}
		},
		data() {
			return {
				providerList: []
			}
		},
		mounted() {
			uni.getProvider({
				service: 'oauth',
				success: (result) => {
					// console.log(result.provider)
					this.providerList = result.provider.map((value) => {
						let providerName = '';
						let icon = ''
						let bgColor = ''
						switch (value) {
							case 'weixin':
								providerName = '微信登录'
								// 自己在这个位置添加上需要渲染的信息 如 icon bgColor
								icon = 'icon-weixin'
								bgColor = 'bg-success'
								break;
							case 'qq':
								providerName = 'QQ登录'
								icon = 'icon-QQ'
								bgColor = 'bg-primary'
								break;
							case 'sinaweibo':
								providerName = '新浪微博登录'
								icon = 'icon-xinlangweibo'
								bgColor = 'bg-warning'
								break;
						}
						// 返回的时候
						return {
							name: providerName,
							id: value,
							icon:icon,
							bgColor:bgColor
						}
					});
		
				},
				fail: (error) => {
					console.log('获取登录通道失败', error);
				}
			});
		},
		methods: {
			// 登录
			login(item){
				// console.log('###',item)
				// 微信需要先login一下,才能执行里面的uni.getUserInfo
				// 这个uni.login的工具函数,可以渲染出来微信登录的页面
				uni.login({
					provider:item.id,
					success:res => {
						// console.log(res)
						// 获取用户信息
						uni.getUserInfo({
							provider:item.id,//'weixin'
						    success:(infoRes) =>{
								// console.log('####',infoRes)
								// {
								// 	"errMsg": "getUserInfo:ok",
								// 	"userInfo": {
								// 		"openId": "oRrdQtzJovVH1ZbCqvf9rQ",
								// 		"nickName": "不争",
								// 		"gender": 1,
								// 		"city": "白山",
								// 		"province": "吉林",
								// 		"country": "中国",
								// 		"avatarUrl": "http://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJYwJfvYwOp29uZAvfRoPSMvo357ibaGh79IdZ40ja3kQS9Sp7VTWhUHcg/132",
								// 		"unionId": "oU5YytxKvy2K0oUftFxmm4"
								// 	}
								// }
								let obj = {
									provider:item.id, // weixin/weibo/qq
									openid :infoRes.userInfo.openId,// 唯一id
									expires_in:0,// 过期时间
									nickName:infoRes.userInfo.nickName, // 微信的昵称
									avatarUrl:infoRes.userInfo.avatarUrl// 微信头像地址
								}
								// console.log(obj)
								// 从微信/qq拿到的信息提交给后端。
								this.loginEvent(obj)
								
							},	
							
						})
					}
				})
			},
			
			// 拿到第三方来的登录信息请求后端。
			loginEvent(data){
				this.$H.post('/user/otherlogin',data)
				.then(res=>{
					// 修改vuex的state,持久化存储
					// this.$store.commit('login',this.$U.formatUserinfo(res))
					this.$store.dispatch('login',this.$U.formatUserinfo(res))
					
					// 返回上一页
					if (this.back){
						uni.navigateBack({
							delta:1
						})
					}
					uni.showToast({
						title:'登录成功',
						icon:'none'
					})	
				})
			},
			
			// #ifdef MP-WEIXIN
			// 如果简单获取用户信息使用 button微信内置的事件就够了
			// 如果想要走后台必然绕不开openid,这个时候就需要uni.login获取code吗再通过我们的服务器获取openid进行数据存储了。
			mpGetUserInfo(result){
				console.log(result) // res是拿不到唯一标识的
				// console.log(result.detail.userInfo.nickName)
				// console.log(result.detail.userInfo.gender)
				// console.log(result.detail.userInfo.avatarUrl)
				// 需要调用login方法拿到code然后请求后端,后端发送给服务器appid+screetkey,这个时候服务器才会
				// 给我返回openid
				uni.showLoading({ title: '登录中...', mask: true });
				// 获取失败
				if (result.detail.errMsg !== 'getUserInfo:ok') {
					uni.hideLoading();
					uni.showModal({
						title: '获取用户信息失败',
						content: '错误原因' + result.detail.errMsg,
						showCancel: false
					});
					return;
				}
				let userinfo = result.detail.userInfo;
				uni.login({
				  provider: 'weixin',
				  success:  (res)=>{
				    // console.log(res);
					// {code: "071vxLuZ0vxS8V17f7vZ03gLuZ0vxLuo"
					// errMsg: "login:ok"}
					this.MpLogin({
						url:"/wxlogin",
						code:res.code,
						nickName:userinfo.nickName,
						avatarUrl:userinfo.avatarUrl
					})
				  },
				 complete: () => {
				  	uni.hideLoading();
				  }
				});
			},
			// #endif
			
			// #ifdef MP-WEIXIN
			// 后端拿到了code,nickname,avatarurl
			// 后端拿着code换取openid,得到了唯一标示,
			// 然后后端把nickname和avatarurl和openid进行存储。
			MpLogin(options){
				this.$H.post(options.url,{
					code:options.code,
					nickName:options.nickName,
					avatarUrl:options.avatarUrl
				}).then(data=>{
					// console.log(data) // data是空的但是代码流程没啥问题。
					// 修改vuex的state,持久化存储
					this.$store.commit('login',this.$U.formatUserinfo(data))
					// 返回上一页
					if(this.back){
						uni.navigateBack({
							delta: 1
						});
					}
					uni.showToast({
						title: '登录成功',
						icon: 'none'
					});
				}).catch(err=>{
					console.log(err)
				});
			},
			// #endif
			
		}
	}
</script>

<style>

</style>

4 小程序上线(思路)

1 注意小程序体积不超过2mb

2 所以Hbuilder打包的时候要配置manifest.json

image-20200521213053680

image-20200521213139389

3 小程序网页后台配置合法域名

image-20200521213243269

4 填写好基本信息后提交审核(未完待续)。

image-20200521213327497

二 app实现热更新

0 关于更新部分代码

ps:直接看注释就好了

App.vue

<script>
export default {
	onLaunch: function() {
		console.log('App Launch');
		
		// 检测更新
		// #ifdef APP-PLUS
		this.$U.update()
		// #endif
		
		// 网络更新
		this.$U.onNetWork()
		
		// 初始化用户登录状态
		this.$store.dispatch('initUser')
	},
	onShow: function() {
		console.log('App Show');
	},
	onHide: function() {
		console.log('App Hide');
	}
};
</script>

Util.js

...
update(showToast = false){
		// #ifdef APP-PLUS
		plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) { 
			$H.post('/update',{
				ver:widgetInfo.version,  // 打包后该参数可以获取当前app的版本号,发给服务端,服务端判断是否更新
			}).then((data) => {
				// 成功
				if (!data.url){
					// 无需更新
					if(showToast){
						uni.showToast({ title: '无需更新',icon:"none" })
					}
					return 
				}
				// 服务端返回了,更新的oss的包地址
				uni.showModal({
					title: '发现新的版本',
					content: '最新版本:'+data.version,
					cancelText: '放弃更新',
					confirmText: '立即更新',
					success: res => {
						if(!res.confirm) return;
						// 然后根据服务端发来的包地址,然后进行下载。
						uni.downloadFile({
							url: data.url,  
							success: (downloadResult) => {  
								if (downloadResult.statusCode === 200) {  
									// 下载完了,然后用plus.runtime.install 安装下
									plus.runtime.install(downloadResult.tempFilePath, {  
										force: false  
									}, function() {  
										console.log('install success...');  
										// 安装完了然后从新启动更新上。然后就完事儿了。
										plus.runtime.restart();  
									}, function(e) {  
										console.error('install fail...');  
									});  
								}  
							}  
						});  
					}
				});
				
			});
			
		});  
		// #endif  
	},
...

about.vue

<template>
	<view>
		<view class="flex align-center justify-center flex-column pt-4 pb-3">
			<image src="/static/common/nothing.png" style="width: 300rpx;height: 300rpx;" class="rounded-circle"></image>
			<text class="font text-muted mt-2">version {{version}}</text>
		</view>
		<uni-list-item title="新版本检测" @click="update"></uni-list-item>
		<uni-list-item title="社区用户协议"></uni-list-item>
	</view>
</template>

<script>
	import uniListItem from '@/components/uni-ui/uni-list-item/uni-list-item.vue';
	export default {
		components: {
			uniListItem
		},
		data() {
			return {
				version:''
			}
		},
		onLoad() {
			// #ifdef APP-PLUS
			plus.runtime.getProperty(plus.runtime.appid, (widgetInfo)=>{ 
				this.version = widgetInfo.version;
			})
			// #endif
		},
		methods: {
			update(){
				this.$U.update(true)
			}
		}
	}
</script>

<style>

</style>

1 首先先云打包一个apk出来

image-20200522163513767

image-20200522163604262

2 制作热更新包

image-20200522164114153

image-20200522164221596

把这个文件,放到oss上面,然后把url和版本号存放到你的数据库里面。这样前端就能拿得到了。

image-20200522164718756

每次热更新请求的就是这个wgt文件,然后plus拿着这个文件更新app。

3 注意事项

1 比如你的你云打包的时候HBuildX是 2.7.0
2 但是你制作wgt更新包的时候是HBuildX是 2.7.2
这个时候就不能采取热更新了,因为编译环境已经发生了改变,这个时候需要全更新。

全更新参考文档:https://ask.dcloud.net.cn/article/34972

热更新参考文档:https://ask.dcloud.net.cn/article/35667

Uni-app运行环境版本和编译器版本不一致的问题:https://ask.dcloud.net.cn/article/35627

四 app上线(待定)

配置图标:

image-20200522173716895

andriod证书问题:

参考官方文档:https://ask.dcloud.net.cn/article/35777

首先如果没有java环境首先下载jre环境

https://www.oracle.com/technetwork/java/javase/downloads/index.html

然后生成签名证书:

keytool -genkey -alias mingyantest -keyalg RSA -keysize 2048 -validity 36500 -keystore /Users/abc/Desktop/mingyantest.keystore
  • testalias是证书别名,可修改为自己想设置的字符,建议使用英文字母和数字
  • test.keystore是证书文件名称,可修改为自己想设置的文件名称,也可以指定完整文件路径

image-20200525162354415

实际上线的时候再考虑其他配置(略)

![image-20200525164229509](33 各个端适配上线.assets/image-20200525164229509.png)

五 支付宝小程序调试(略)

1 下载支付宝小程序调试器

2 如果出现莫名其妙报错,在hbuilder上面直接发行包,然后使用支付宝小程序进行调试。

posted @ 2020-05-25 18:49  张明岩  阅读(623)  评论(0编辑  收藏  举报