阿里icon图标浏览器预览没有问题,但是在APP中不显示
将src: url('//at.alicdn.com/t/font_1231814_9dilkcfckhr.ttf') format('truetype');
改为src: url('https://at.alicdn.com/t/font_1231814_9dilkcfckhr.ttf') format('truetype');
今天用手机调试项目时发现在浏览器中正常的图标,到手机上不显示了,经过一番查找发现在引用链接前加上‘https:’就可以了!!!
将src: url('//at.alicdn.com/t/font_1231814_9dilkcfckhr.ttf') format('truetype');
改为src: url('https://at.alicdn.com/t/font_1231814_9dilkcfckhr.ttf') format('truetype');
今天用手机调试项目时发现在浏览器中正常的图标,到手机上不显示了,经过一番查找发现在引用链接前加上‘https:’就可以了!!!
nvue页面引用iconfont图标经验分享
前言:发现社区在对nvue使用iconfont图标的文章还是比较少,在这里刚好遇到了,那就分享一下我的解决方法。
在项目中遇到了需要在nvue里使用iconfont图标,
刚开始照着社区搜索的答案:https://ask.dcloud.net.cn/question/64622
这样引入css文件:
<style src="@/common/iconfont.css"></style>
然后再使用
<div class="iconfont icon-like"></div>
真机运行后,好家伙,纹丝不动,气人的是还没法调试……
再次搜索发现社区都是只言片语,于是将搜索范围扩大到百度,发现了玄机。
下面给出正确打开方式:
<!--使用unicode的形式-->
<text class="iconfont icon-like"></text>
<!--图标内容使用data里的变量-->
<text :style="{fontFamily:'iconfont',color:'red',fontSize:'40px'}">{{fontName}}</text>
data:{
return {
fontName: "\ue64e",
}
},
created() {
var domModule = weex.requireModule("dom");
domModule.addRule('fontFace', {
'fontFamily': 'iconfont',
'src': "url(\'http://at.alicdn.com/t/font_876280_0c92t3na1oei.ttf\')"
})
}
.iconfont {
font-family: iconfont;
}
.icon-like {
width: 36px;
height: 36px;
font-size: 34px;
}
上面的代码展示了两种图标使用方式,自行选择其中一种使用,亲测有效。
--------------------------------下面展示一些坑点-----------------------------------
坑点一:
载入的字体文件ttf文件,url前面一定得有协议头,如http,iconfont上面是没有协议头的,应该是为了自适应支持https
错误写法:( 分分给你一个方框框看看~)
'src': "url(\'//at.alicdn.com/t/font_876280_0c92t3na1oei.ttf\')"
正确写法是:(需要加上协议头)
'src': "url(\'http://at.alicdn.com/t/font_876280_0c92t3na1oei.ttf\')"
坑点二:
上面两种引用形式,使用的内容编码其实是不一样的,这个可以在iconfont.com上面找到哈。
第一种引用方式的code获取方式:
1.鼠标放在图标上,选择右上角的按钮『编辑』
2.弹出窗口后,复制里面的16进制的Unicode码:e64e,使用时,需要在前面加上\u,即完整编辑为:\ue64e。
第二种引用方式的code获取方式:
1.鼠标放在图标上,直接复制即可。
前言:发现社区在对nvue使用iconfont图标的文章还是比较少,在这里刚好遇到了,那就分享一下我的解决方法。
在项目中遇到了需要在nvue里使用iconfont图标,
刚开始照着社区搜索的答案:https://ask.dcloud.net.cn/question/64622
这样引入css文件:
<style src="@/common/iconfont.css"></style>
然后再使用
<div class="iconfont icon-like"></div>
真机运行后,好家伙,纹丝不动,气人的是还没法调试……
再次搜索发现社区都是只言片语,于是将搜索范围扩大到百度,发现了玄机。
下面给出正确打开方式:
<!--使用unicode的形式-->
<text class="iconfont icon-like"></text>
<!--图标内容使用data里的变量-->
<text :style="{fontFamily:'iconfont',color:'red',fontSize:'40px'}">{{fontName}}</text>
data:{
return {
fontName: "\ue64e",
}
},
created() {
var domModule = weex.requireModule("dom");
domModule.addRule('fontFace', {
'fontFamily': 'iconfont',
'src': "url(\'http://at.alicdn.com/t/font_876280_0c92t3na1oei.ttf\')"
})
}
.iconfont {
font-family: iconfont;
}
.icon-like {
width: 36px;
height: 36px;
font-size: 34px;
}
上面的代码展示了两种图标使用方式,自行选择其中一种使用,亲测有效。
--------------------------------下面展示一些坑点-----------------------------------
坑点一:
载入的字体文件ttf文件,url前面一定得有协议头,如http,iconfont上面是没有协议头的,应该是为了自适应支持https
错误写法:( 分分给你一个方框框看看~)
'src': "url(\'//at.alicdn.com/t/font_876280_0c92t3na1oei.ttf\')"
正确写法是:(需要加上协议头)
'src': "url(\'http://at.alicdn.com/t/font_876280_0c92t3na1oei.ttf\')"
坑点二:
上面两种引用形式,使用的内容编码其实是不一样的,这个可以在iconfont.com上面找到哈。
第一种引用方式的code获取方式:
1.鼠标放在图标上,选择右上角的按钮『编辑』
2.弹出窗口后,复制里面的16进制的Unicode码:e64e,使用时,需要在前面加上\u,即完整编辑为:\ue64e。
第二种引用方式的code获取方式:
1.鼠标放在图标上,直接复制即可。
方法return 在app调试中是空,或者计算属性返回在真机调试中也是空的解决方法
今天在将应用放到安卓手机调试的过程中发现原本可以显示内容在h5上可以显示却在真机调试上为空,类似代码如下 无法return出内容,
demo代码
<view class="page">{{vifshow(2)}}</view>
methods: {
vifshow: function(id) {
if (id == 1) {
return("sdas")
} else if(id==2) {
return("2323")
}}
,}
经过无数次的试验发现将测试代码放到新创建的空项目中调试发现可以使用于是考虑没准是编译器版本的问题内容见 发现果然新版的是而老版的配置文件没有这个usingComponents选项,添加后在app上运行就正常了
"app-plus": {
"usingComponents":true //是否启用`自定义组件模式`,为true表示新的`自定义组件模式` ,否则为`template模板模式`
}
今天在将应用放到安卓手机调试的过程中发现原本可以显示内容在h5上可以显示却在真机调试上为空,类似代码如下 无法return出内容,
demo代码
<view class="page">{{vifshow(2)}}</view>
methods: {
vifshow: function(id) {
if (id == 1) {
return("sdas")
} else if(id==2) {
return("2323")
}}
,}
经过无数次的试验发现将测试代码放到新创建的空项目中调试发现可以使用于是考虑没准是编译器版本的问题内容见 发现果然新版的是而老版的配置文件没有这个usingComponents选项,添加后在app上运行就正常了
"app-plus": {
"usingComponents":true //是否启用`自定义组件模式`,为true表示新的`自定义组件模式` ,否则为`template模板模式`
}
收起阅读 »
Uni-App微信小程序页面间通信的HOOK方式
过去两年多一直在H5+环境里开发,刚接触uni-app不久,在h5+里可以方便的通过
WebviewObject plus.webview.create( url, id, styles, extras );
里的extras传递参数给其他页面,也可以通过
var index_main = plus.webview.getWebviewById("index_main");
index_main.evalJS('update_bill_badge_num()');
来调用已经打开的页面上的方法,或者定义一个接收参数的函数,把参数传递到已经打开的页面里
到了uni-app里的小程序,小的一些参数我可以通过/page/home/home?abc=123这种方式,或者通过LocalStoreage来传递,但是如果是比较大的json,通过第一种方式肯定不行,通过LS方式又太慢了,通过Vue.protoype.xxx来挂载一些常量还可以,变量是没用的,在这个页里修改了,在另外一个页面里还是原来的值。
我在网上看到这篇文章《微信小程序页面间通信的5种方式》https://segmentfault.com/a/1190000008895441 里的方式五:通过hack方法直接调用通信页面的方法,感觉这不就是H5+里的通过webview来传值的方式吗?
然后我就在微信小程序的开发环境里实验成功了
微信小程序里:首先定义了一个pages.js文件,在小程序根目录新建了一个plugin目录,然后放在里面
====================
pages.js的内容:
// plugin/pages.js
// 缓存pageModel,一个简要实现
export default class PM {
constructor() {
this.$$cache = {};
}
add(pageModel) {
let pagePath = this._getPageModelPath(pageModel);
this.$$cache[pagePath] = pageModel;
}
get(pagePath) {
return this.$$cache[pagePath];
}
delete(pageModel) {
try {
delete this.$$cache[this._getPageModelPath(pageModel)];
} catch (e) {
}
}
_getPageModelPath(page) {
// 关键点
return page.__route__;
}
}
====================
然后在小程序的app.js里引入:
//app.js
import PageModel from './plugin/pages.js'; //引入
App({
pages: new PageModel(), //挂载一个pages对象
onLaunch: function () {
},
globalData: {
userInfo: null
}
})
====================
在页面A里:
// pageA
let app = getApp();
Page({
data: {
helloMsg: 'hello from PageA'
},
onLoad() {
//加入页面缓存对象
app.pages.add(this);
console.log('Page A');
},
onShow(){
console.log(this.data.helloMsg);
},
gotoC() {
wx.navigateTo({
url: '/pages/home/home'
});
},
sayHello(msg) {
this.setData({
helloMsg: msg
});
},
writeHello(msg){
console.log(msg);
}
});
====================
然后在页面C里:
//pageC
let app = getApp();
Page({
onLoad(){
console.log('Page C');
this.doSomething();
},
doSomething() {
console.log('do PageC method\n\n');
// 见证奇迹的时刻
let data_msg = app.pages.get('pages/index/index').data.helloMsg;
console.log('------获取A的数据------');
console.log( data_msg );
console.log('----------------------\n\n');
console.log('------改变A的数据------');
app.pages.get('pages/index/index').sayHello('hello from PageC');
console.log('----------------------\n\n');
console.log('------调用A的方法------');
app.pages.get('pages/index/index').writeHello('PageC call PageA method!');
console.log('----------------------\n\n');
}
});
在页面C里成功获取了页面A的变量,还能调用页面A的方法,如果改变了页面A的变量,,在从页面C回到页面A时,如果显示这个被修改的变量,可以看到变量内容的确被修改了。看到这个实验的结果,我喜出望外,打算把它引入到uni-app中:
一开始我就想仿照微信小程序的方式:
====================
在main.js里
import Vue from 'vue'
import App from './App'
import store from './store'
import PageModel from './pages.js'; //引入
//省略其他内容
App.mpType = 'app'
const app = new Vue({
//加入PageModel
pages: new PageModel(),
...App
})
app.$mount()
====================
又或者放在App.vue里:
<script>
import PageModel from './pages.js';
export default {
//加入PageModel
pages: new PageModel(),
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/* 每个页面公共css */
</style>
然后在PageA里:
var app = getApp();
app.pages.add(this);
两种方法都不行,都报错误,应该是没有正确的把pages挂载到app上去。
console.log( app );
发现其实还是挂载成功了的,在很深的层里:
这样是成功的
app.$vm.$options.pages.add(this);
console.log( app.$vm.$options.pages );
在PageC里:
var page_index_obj = app.$vm.$options.pages.get('pages/index/index');
var page_index_obj_index_data = page_index_obj._data.index_data;
console.log( page_index_obj_index_data )
我对uni-app不太熟悉,对Vue也只是刚开始学习使用,然后搜到社区里一篇文章《getApp() 挂载实例方法》https://ask.dcloud.net.cn/article/35810 ,应该就是我想要的东西,但是说的太模糊了,dcloud的源码实在太长了,看不太懂,直接加到hooks也是不行的,能否指教一下,怎么把自己写的对象,挂载上去。
const hooks = [
'onHide',
'onError',
'onPageNotFound',
'onUniNViewMessage',
//'pages', //无效
];
我现在可以实现数据的传递了,但是下面这样的写法,实在是有点丑陋
app.$vm.$options.pages.add(this);
app.$vm.$options.pages.get('pages/index/index')._data.index_data;‘
另外记得在页面的onUnload里,记得要从页面栈里删除当前对象
onUnload(){
app.$vm.$options.pages.delete(this);
},
PS.我已经在项目里使用了上述方法了,相当于在app.$vm.$options.pages里建了一个栈,而且里面的数据和方法都是可以调用的,,比如关闭当前页面的时候,把本页的数据传递到上一个页面里,不知道大家还有更好的方法~
我回复了上文作者,一直没回应我,可能是太忙了,上次文章也没排版好,这次重发一遍。
过去两年多一直在H5+环境里开发,刚接触uni-app不久,在h5+里可以方便的通过
WebviewObject plus.webview.create( url, id, styles, extras );
里的extras传递参数给其他页面,也可以通过
var index_main = plus.webview.getWebviewById("index_main");
index_main.evalJS('update_bill_badge_num()');
来调用已经打开的页面上的方法,或者定义一个接收参数的函数,把参数传递到已经打开的页面里
到了uni-app里的小程序,小的一些参数我可以通过/page/home/home?abc=123这种方式,或者通过LocalStoreage来传递,但是如果是比较大的json,通过第一种方式肯定不行,通过LS方式又太慢了,通过Vue.protoype.xxx来挂载一些常量还可以,变量是没用的,在这个页里修改了,在另外一个页面里还是原来的值。
我在网上看到这篇文章《微信小程序页面间通信的5种方式》https://segmentfault.com/a/1190000008895441 里的方式五:通过hack方法直接调用通信页面的方法,感觉这不就是H5+里的通过webview来传值的方式吗?
然后我就在微信小程序的开发环境里实验成功了
微信小程序里:首先定义了一个pages.js文件,在小程序根目录新建了一个plugin目录,然后放在里面
====================
pages.js的内容:
// plugin/pages.js
// 缓存pageModel,一个简要实现
export default class PM {
constructor() {
this.$$cache = {};
}
add(pageModel) {
let pagePath = this._getPageModelPath(pageModel);
this.$$cache[pagePath] = pageModel;
}
get(pagePath) {
return this.$$cache[pagePath];
}
delete(pageModel) {
try {
delete this.$$cache[this._getPageModelPath(pageModel)];
} catch (e) {
}
}
_getPageModelPath(page) {
// 关键点
return page.__route__;
}
}
====================
然后在小程序的app.js里引入:
//app.js
import PageModel from './plugin/pages.js'; //引入
App({
pages: new PageModel(), //挂载一个pages对象
onLaunch: function () {
},
globalData: {
userInfo: null
}
})
====================
在页面A里:
// pageA
let app = getApp();
Page({
data: {
helloMsg: 'hello from PageA'
},
onLoad() {
//加入页面缓存对象
app.pages.add(this);
console.log('Page A');
},
onShow(){
console.log(this.data.helloMsg);
},
gotoC() {
wx.navigateTo({
url: '/pages/home/home'
});
},
sayHello(msg) {
this.setData({
helloMsg: msg
});
},
writeHello(msg){
console.log(msg);
}
});
====================
然后在页面C里:
//pageC
let app = getApp();
Page({
onLoad(){
console.log('Page C');
this.doSomething();
},
doSomething() {
console.log('do PageC method\n\n');
// 见证奇迹的时刻
let data_msg = app.pages.get('pages/index/index').data.helloMsg;
console.log('------获取A的数据------');
console.log( data_msg );
console.log('----------------------\n\n');
console.log('------改变A的数据------');
app.pages.get('pages/index/index').sayHello('hello from PageC');
console.log('----------------------\n\n');
console.log('------调用A的方法------');
app.pages.get('pages/index/index').writeHello('PageC call PageA method!');
console.log('----------------------\n\n');
}
});
在页面C里成功获取了页面A的变量,还能调用页面A的方法,如果改变了页面A的变量,,在从页面C回到页面A时,如果显示这个被修改的变量,可以看到变量内容的确被修改了。看到这个实验的结果,我喜出望外,打算把它引入到uni-app中:
一开始我就想仿照微信小程序的方式:
====================
在main.js里
import Vue from 'vue'
import App from './App'
import store from './store'
import PageModel from './pages.js'; //引入
//省略其他内容
App.mpType = 'app'
const app = new Vue({
//加入PageModel
pages: new PageModel(),
...App
})
app.$mount()
====================
又或者放在App.vue里:
<script>
import PageModel from './pages.js';
export default {
//加入PageModel
pages: new PageModel(),
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/* 每个页面公共css */
</style>
然后在PageA里:
var app = getApp();
app.pages.add(this);
两种方法都不行,都报错误,应该是没有正确的把pages挂载到app上去。
console.log( app );
发现其实还是挂载成功了的,在很深的层里:
这样是成功的
app.$vm.$options.pages.add(this);
console.log( app.$vm.$options.pages );
在PageC里:
var page_index_obj = app.$vm.$options.pages.get('pages/index/index');
var page_index_obj_index_data = page_index_obj._data.index_data;
console.log( page_index_obj_index_data )
我对uni-app不太熟悉,对Vue也只是刚开始学习使用,然后搜到社区里一篇文章《getApp() 挂载实例方法》https://ask.dcloud.net.cn/article/35810 ,应该就是我想要的东西,但是说的太模糊了,dcloud的源码实在太长了,看不太懂,直接加到hooks也是不行的,能否指教一下,怎么把自己写的对象,挂载上去。
const hooks = [
'onHide',
'onError',
'onPageNotFound',
'onUniNViewMessage',
//'pages', //无效
];
我现在可以实现数据的传递了,但是下面这样的写法,实在是有点丑陋
app.$vm.$options.pages.add(this);
app.$vm.$options.pages.get('pages/index/index')._data.index_data;‘
另外记得在页面的onUnload里,记得要从页面栈里删除当前对象
onUnload(){
app.$vm.$options.pages.delete(this);
},
PS.我已经在项目里使用了上述方法了,相当于在app.$vm.$options.pages里建了一个栈,而且里面的数据和方法都是可以调用的,,比如关闭当前页面的时候,把本页的数据传递到上一个页面里,不知道大家还有更好的方法~
我回复了上文作者,一直没回应我,可能是太忙了,上次文章也没排版好,这次重发一遍。
收起阅读 »tp5.1+uni-app开发移动app或者小程序
b站视频 全栈开发简单教程
https://www.bilibili.com/video/av54175781?from=search&seid=8237648774832145478
b站视频 全栈开发简单教程
https://www.bilibili.com/video/av54175781?from=search&seid=8237648774832145478
键盘弹起时背景图片挤压(一般用于登录页面)
使用uni.getSystemInfoSync()获取可用宽高,最后设置到view上即可。
使用uni.getSystemInfoSync()获取可用宽高,最后设置到view上即可。
原生层级覆盖问题解决方案
一、uni-app的原生层级覆盖
另见文档:https://uniapp.dcloud.io/component/native-component**
二、5+App的原生对象层级覆盖
为了提升性能,5+提供了一批原生对象,比如plus.video、plus.map、plus.nativeObj、plus.nativeUI、plus.webview、plus.barcode、plus.gallery.pick、plus.camera
虽然提升了性能,但带来了前端组件无法覆盖原生控件的层级问题,为了解决这个问题,有2种方案:
- plus.nativeObj.view
简称nview,它是一个原生的类画布的控件。
API文档详见:https://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View
plus.nativeObj.view的API比较原始,可以画出任何界面,但plus.nativeObj.view有3个问题:1. api很底层,开发比较复杂;2. 不支持动画;3. 不支持内部滚动。
plus.nativeObj.view的层级是最高的,它高于子webview、高于uni-app的subnvue。
- 子webview
子webview的意思是创建一个新的非全屏webview,盖住原生界面对象。
子webview没有plus.nativeObj.view的限制,可以随意覆盖。
子webview会比plus.nativeObj.view多占用一些内存。所以如果你要覆盖的内容很简单,plus.nativeObj.view可以简单实现,也没必要用子webview。
子webview可以设zindex,来调节多个子webview的层级。但不建议使用太多子webview,影响性能。
一、uni-app的原生层级覆盖
另见文档:https://uniapp.dcloud.io/component/native-component**
二、5+App的原生对象层级覆盖
为了提升性能,5+提供了一批原生对象,比如plus.video、plus.map、plus.nativeObj、plus.nativeUI、plus.webview、plus.barcode、plus.gallery.pick、plus.camera
虽然提升了性能,但带来了前端组件无法覆盖原生控件的层级问题,为了解决这个问题,有2种方案:
- plus.nativeObj.view
简称nview,它是一个原生的类画布的控件。
API文档详见:https://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.View
plus.nativeObj.view的API比较原始,可以画出任何界面,但plus.nativeObj.view有3个问题:1. api很底层,开发比较复杂;2. 不支持动画;3. 不支持内部滚动。
plus.nativeObj.view的层级是最高的,它高于子webview、高于uni-app的subnvue。
- 子webview
子webview的意思是创建一个新的非全屏webview,盖住原生界面对象。
子webview没有plus.nativeObj.view的限制,可以随意覆盖。
子webview会比plus.nativeObj.view多占用一些内存。所以如果你要覆盖的内容很简单,plus.nativeObj.view可以简单实现,也没必要用子webview。
子webview可以设zindex,来调节多个子webview的层级。但不建议使用太多子webview,影响性能。
收起阅读 »uniapp app 端调微信支付接口
uni-app 官方文档支付接口如下:
uni.requestPayment({
provider: provider, // wxpay、alipay
orderInfo: 'orderInfo', //微信、支付宝订单数据
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
文档中 orderInfo 的格式没写清楚,今天刚好在研究支付,发现调起微信支付接口的 orderInfo 可以是对象,也可以是对象字符串,比如:
let obj = {
appid: 应用ID,
noncestr: 随机字符串,
package: 'Sign=WXPay', // 固定值,以微信支付文档为主
partnerid: 商户号,
prepayid: 预支付交易会话ID,
timestamp: 时间戳,
sign: 签名 // 根据签名算法生成签名
}
// 第一种写法,传对象
let orderInfo = obj
// 第二种写法,传对象字符串
let orderInfo = JSON.stringify(obj)
uni.requestPayment({
provider: 'wxpay',
orderInfo: orderInfo, //微信、支付宝订单数据
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
-
Tips:
当时做项目所传的参数和签名都正确,结果还是返回 -1,查了半天结果用的是 deCloud 的标准定义基座,它的包名跟自己的 app 申请的包不一样,导致不能正常调起微信支付接口,但支付宝的可以。更换自定义基座,填上自己的包名,证书等,然后打包安装运行就 ok 了
uni-app 官方文档支付接口如下:
uni.requestPayment({
provider: provider, // wxpay、alipay
orderInfo: 'orderInfo', //微信、支付宝订单数据
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
文档中 orderInfo 的格式没写清楚,今天刚好在研究支付,发现调起微信支付接口的 orderInfo 可以是对象,也可以是对象字符串,比如:
let obj = {
appid: 应用ID,
noncestr: 随机字符串,
package: 'Sign=WXPay', // 固定值,以微信支付文档为主
partnerid: 商户号,
prepayid: 预支付交易会话ID,
timestamp: 时间戳,
sign: 签名 // 根据签名算法生成签名
}
// 第一种写法,传对象
let orderInfo = obj
// 第二种写法,传对象字符串
let orderInfo = JSON.stringify(obj)
uni.requestPayment({
provider: 'wxpay',
orderInfo: orderInfo, //微信、支付宝订单数据
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
-
Tips:
当时做项目所传的参数和签名都正确,结果还是返回 -1,查了半天结果用的是 deCloud 的标准定义基座,它的包名跟自己的 app 申请的包不一样,导致不能正常调起微信支付接口,但支付宝的可以。更换自定义基座,填上自己的包名,证书等,然后打包安装运行就 ok 了
献礼“618”,1700+集前端视频教程免费看
一年一度“618”,岁岁年年狂剁手。
随着网购时代的到来,越来越多的剁手节让大家谜一样的沉浸其中,无法自拔,什么618、双十一、双十二、双旦等等
年前定下的攒钱目标还没开始就要宣告结束
这就是人生不得不承认的事实
然而比618来得更猝不及防的
是各大电商的营销文案
一个比一个精彩
一个比一个诱惑
所谓清空购物车一时爽,事后剁手火葬场
小妙深知购物狂+剁手党的疯狂
也深知这样一个“节日”对自媒体人来说意味着什么
当然是拼文案拼营销拼姿势啊
反正,钱是越花越少的
经验是越攒越多的
精彩文案给你摆在这
这个手你剁不剁?
小妙作为剁手大军的一员,深深了解大家的纠结与痛苦
而我今年就不一样了,不但不剁手,还可以免费学到知识
免费看?免费?是的,你没看错,真的免费!!!
即日起,注册妙味视频平台的新用户,即可获得价值239元包含1700+集的前端优质视频教程的7天观看权限
无论你是在学布局还是在学小程序,亦或是在学Vue、react,这里应有尽有,爱学习的你,还没心动么,心动了的话就赶快行动起来吧
活动详情见海报:
一年一度“618”,岁岁年年狂剁手。
随着网购时代的到来,越来越多的剁手节让大家谜一样的沉浸其中,无法自拔,什么618、双十一、双十二、双旦等等
年前定下的攒钱目标还没开始就要宣告结束
这就是人生不得不承认的事实
然而比618来得更猝不及防的
是各大电商的营销文案
一个比一个精彩
一个比一个诱惑
所谓清空购物车一时爽,事后剁手火葬场
小妙深知购物狂+剁手党的疯狂
也深知这样一个“节日”对自媒体人来说意味着什么
当然是拼文案拼营销拼姿势啊
反正,钱是越花越少的
经验是越攒越多的
精彩文案给你摆在这
这个手你剁不剁?
小妙作为剁手大军的一员,深深了解大家的纠结与痛苦
而我今年就不一样了,不但不剁手,还可以免费学到知识
免费看?免费?是的,你没看错,真的免费!!!
即日起,注册妙味视频平台的新用户,即可获得价值239元包含1700+集的前端优质视频教程的7天观看权限
无论你是在学布局还是在学小程序,亦或是在学Vue、react,这里应有尽有,爱学习的你,还没心动么,心动了的话就赶快行动起来吧
活动详情见海报:
收起阅读 »Android平台云端打包证书使用说明
HBuilderX中开发完成发布为原生App提交云端打包时,在“App云端打包”界面中Android平台需要选择签名证书:
支持以下证书类型:
- 使用自有证书
开发者自己生成证书,正式发布应用时推荐使用此类型证书 - 使用公共测试证书
使用DCloud云端默认的测试证书,仅限开发测试时使用。由于此证书对所有开发者公开,正式发布应用使用此证书存在安全隐患 - 使用DCloud老版证书
兼容老项目使用之前的DCloud证书时选择,此证书将废弃,尽量不要使用此证书
关于Android证书的用途
证书是一个开发者的身份标志,对Android系统而言。使用一个证书签发的App,是属于同一个开发者的App。
举个极端的例子,如果你的应用证书泄露,那么别人可以用这个证书签名一个仿冒App,假如包名和你的包名也一样,就可以覆盖安装安卓手机上你之前的包。
当前仅依赖证书校验是不完善的,所以主流的Android应用市场,通过实名认证开发者信息和著作权,强化了App的唯一性。也就是从主流应用市场点更新,不会发生冒充事件。但是通过其他方式安装apk,仍然会发生冒充的可能性。
如果签名不同,即使包名相同,也无法覆盖安装。此时安卓手机会在安装时报错,需要先卸载老的版本,才能安装新版。
证书安全说明
Android的应用安全管理模型,包括包名、证书、应用市场的账户。
包名是公开的,任何人都可以做一个apk包,包名和你的应用包名相同。那么如何防止仿冒包?
- 他人没有你的应用市场账户,就无法在市场发布仿冒包。
- 他人没有你的签名证书。不过这一点,现实中有很多问题,手机用户是没有识别能力的。大多数安卓手机上也无法查看应用的签名信息。
证书使用说明
使用自有证书打包发布
开发者如果已经有自己的安卓证书,可直接使用。
如果没有,使用JDK的keytool工具生成一个,不像Apple证书那样收费,制作Android证书没有费用。
完整教程参考Android平台签名证书(.keystore)生成指南
注意以下问题:
- 证书文件密码(storepass)和证书密码(keypass)必须一致,HBuilder|HBuilderX要求这两个密码一致
- 证书别名使用英文字母或数字(老版本HBuilder不支持使用中文别名)
- 证书名称建议使用英文字母或数字,避免使用中文
生成证书后注意保存,不要泄露。
提交云端打包时,如下图配置:
提交云端打包后,打包机会立即删除的证书,不会保存或泄露证书,请放心使用
<a id="server"/>
使用云端证书(服务器生成的证书)
生成自有证书需要配置jre环境,为了方便开发者快速生成证书云端打包,从HBuilderX3.2.0及以上版本开始支持服务器生成证书。
在App打包界面可以直接勾选“使用云端证书”:
注意:
- 服务器生成的证书绑定应用appid,即每个appid会各自生成证书
- 服务器生成的证书会自动填写证书信息,不支持自定义证书信息,有效期为100年
- 查看或下载服务器生成的证书,请登录DCloud开发者中心
使用公共测试证书打包
为了方便开发者评估、测试体验,可直接使用公共测试证书打包,免去制作证书的麻烦。
证书信息参考:https://ask.dcloud.net.cn/article/36522
注意:
- 所有开发者都能使用此证书打包
- 证书可以被所有人下载
- 证书信息为Test
使用DCloud公用证书
为了方便开发者评估、测试,或用于一些安全要求不高的场合,老版本HBuilder/HBuilderX提供了公用DCloud证书,免去了开发者制作自有证书的麻烦。
因为此证书包含DCloud公司名称信息,与实际应用的所有者信息描述和省份不符,为了保障开发者利益及安全要求,将废弃此证书。
详情参考https://ask.dcloud.net.cn/article/68
使用DCloud公用证书不影响提交应用市场通过审核。
注意事项
注意证书有一个特点,用A证书打包后,后续新版若改用B证书,会导致升级包无法安装。因为相同包名但签名不同时,Android rom不允许安装新包。所以商用第一版应用发布时,证书一定选择好。
在极端情况下,使用公用证书可能发生应用被仿冒:
- 如果你的应用使用了DCloud公共证书,且
- 应用升级下载新版apk,使用了http链接,被劫持,替换为新包;或手机usb链接到非安全电脑,并允许了该电脑给手机安装应用,且
- 仿冒的新包包名和你的包相同,证书也相同,版本号大于老包,就会升级成功,将手机上你的应用替换为仿冒应用。那么用户在仿冒应用里填写的用户名密码就会被仿冒者获取。
证书的区别如上,如何选择证书,每位开发者根据自己的需求定夺。
HBuilderX中开发完成发布为原生App提交云端打包时,在“App云端打包”界面中Android平台需要选择签名证书:
支持以下证书类型:
- 使用自有证书
开发者自己生成证书,正式发布应用时推荐使用此类型证书 - 使用公共测试证书
使用DCloud云端默认的测试证书,仅限开发测试时使用。由于此证书对所有开发者公开,正式发布应用使用此证书存在安全隐患 - 使用DCloud老版证书
兼容老项目使用之前的DCloud证书时选择,此证书将废弃,尽量不要使用此证书
关于Android证书的用途
证书是一个开发者的身份标志,对Android系统而言。使用一个证书签发的App,是属于同一个开发者的App。
举个极端的例子,如果你的应用证书泄露,那么别人可以用这个证书签名一个仿冒App,假如包名和你的包名也一样,就可以覆盖安装安卓手机上你之前的包。
当前仅依赖证书校验是不完善的,所以主流的Android应用市场,通过实名认证开发者信息和著作权,强化了App的唯一性。也就是从主流应用市场点更新,不会发生冒充事件。但是通过其他方式安装apk,仍然会发生冒充的可能性。
如果签名不同,即使包名相同,也无法覆盖安装。此时安卓手机会在安装时报错,需要先卸载老的版本,才能安装新版。
证书安全说明
Android的应用安全管理模型,包括包名、证书、应用市场的账户。
包名是公开的,任何人都可以做一个apk包,包名和你的应用包名相同。那么如何防止仿冒包?
- 他人没有你的应用市场账户,就无法在市场发布仿冒包。
- 他人没有你的签名证书。不过这一点,现实中有很多问题,手机用户是没有识别能力的。大多数安卓手机上也无法查看应用的签名信息。
证书使用说明
使用自有证书打包发布
开发者如果已经有自己的安卓证书,可直接使用。
如果没有,使用JDK的keytool工具生成一个,不像Apple证书那样收费,制作Android证书没有费用。
完整教程参考Android平台签名证书(.keystore)生成指南
注意以下问题:
- 证书文件密码(storepass)和证书密码(keypass)必须一致,HBuilder|HBuilderX要求这两个密码一致
- 证书别名使用英文字母或数字(老版本HBuilder不支持使用中文别名)
- 证书名称建议使用英文字母或数字,避免使用中文
生成证书后注意保存,不要泄露。
提交云端打包时,如下图配置:
提交云端打包后,打包机会立即删除的证书,不会保存或泄露证书,请放心使用
<a id="server"/>
使用云端证书(服务器生成的证书)
生成自有证书需要配置jre环境,为了方便开发者快速生成证书云端打包,从HBuilderX3.2.0及以上版本开始支持服务器生成证书。
在App打包界面可以直接勾选“使用云端证书”:
注意:
- 服务器生成的证书绑定应用appid,即每个appid会各自生成证书
- 服务器生成的证书会自动填写证书信息,不支持自定义证书信息,有效期为100年
- 查看或下载服务器生成的证书,请登录DCloud开发者中心
使用公共测试证书打包
为了方便开发者评估、测试体验,可直接使用公共测试证书打包,免去制作证书的麻烦。
证书信息参考:https://ask.dcloud.net.cn/article/36522
注意:
- 所有开发者都能使用此证书打包
- 证书可以被所有人下载
- 证书信息为Test
使用DCloud公用证书
为了方便开发者评估、测试,或用于一些安全要求不高的场合,老版本HBuilder/HBuilderX提供了公用DCloud证书,免去了开发者制作自有证书的麻烦。
因为此证书包含DCloud公司名称信息,与实际应用的所有者信息描述和省份不符,为了保障开发者利益及安全要求,将废弃此证书。
详情参考https://ask.dcloud.net.cn/article/68
使用DCloud公用证书不影响提交应用市场通过审核。
注意事项
注意证书有一个特点,用A证书打包后,后续新版若改用B证书,会导致升级包无法安装。因为相同包名但签名不同时,Android rom不允许安装新包。所以商用第一版应用发布时,证书一定选择好。
在极端情况下,使用公用证书可能发生应用被仿冒:
- 如果你的应用使用了DCloud公共证书,且
- 应用升级下载新版apk,使用了http链接,被劫持,替换为新包;或手机usb链接到非安全电脑,并允许了该电脑给手机安装应用,且
- 仿冒的新包包名和你的包相同,证书也相同,版本号大于老包,就会升级成功,将手机上你的应用替换为仿冒应用。那么用户在仿冒应用里填写的用户名密码就会被仿冒者获取。
证书的区别如上,如何选择证书,每位开发者根据自己的需求定夺。
收起阅读 »dcloud集成腾讯广告联盟(优量汇)
摸索了几天终于采取一个不那么好的办法搞定了dcloud集成腾讯广告联盟,特记录下来,希望能给新手朋友一些帮助,安卓我只带过团队,自己也是第一次实际操作,老鸟请忽略。
1、离线打包
2、集成腾讯广告联盟的SDK
3、新增一个启动页
4、新增banner2.0的activity
5、用h5通过native调用activity
1、离线打包
这个官方有详细的介绍了
http://ask.dcloud.net.cn/article/508
说一下我踩过的几个坑
1-1、Module not specified
导入project,不是直接导入,而是先随意新建一个project,然后导入module,否则运行的时候会报错
1-2、Android Studio报错Manifest merger failed with multiple errors
这个提示是因为AndroidManifest.xml中的配置和build.gradle里的配置不一样,手动将build.gradle里的applicationId改成和AndroidManifest.xml的一致就可以正常运行了
2、集成腾讯广告联盟的SDK
2-1、将腾讯广告联盟的jar文件拷贝到项目根目录的libs目录下,
2-2、然后修改build.gradle,dependencies的最后一行加上implementation files('libs/GDTSDK.tbs.4.30.906.jar')(GDTSDK.tbs.4.30.906.jar是刚拷贝的jar的名字)
2-3、修改AndroidMnifest.xml(腾讯广告联盟的文档有描述),就不详细写了
3、新增一个启动activity
3-1、新建一个activity作为启动activity
3-2、启动activity参照腾讯广告联盟的DEMO就可以了,代码略作修改,这里加了一个限制,开屏广告一个小时只展示一次
protected void onCreate(@Nullable Bundle savedInstanceState) {
Long curDate = new Date().getTime();//当前时间
//获取上次时间
SharedPreferences sp = getSharedPreferences("sp_name", Context.MODE_PRIVATE);
String lastSpADTime = sp.getString("lastSpADTime", "0");
Long lastSpADTimeLong = Long.parseLong(lastSpADTime);
if(curDate - lastSpADTimeLong > 3600000) {//超过一个小时则再次显示广告
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
container = (ViewGroup) this.findViewById(R.id.splash_container);
skipView = (TextView) findViewById(R.id.skip_view);
splashHolder = (ImageView) findViewById(R.id.splash_holder);
splashAD = new SplashAD(this, container, skipView, Constants.APPID, getPosId(), this, 0);
//写入上次时间
SharedPreferences.Editor editor = sp.edit();
editor.putString("lastSpADTime", curDate.toString());
editor.apply();
} else {
this.onADDismissed();
}
}
private String getPosId() {
return Constants.SplashPosID;
}
public void onADDismissed() {
this.finish();
//主要改动是在这里,开屏广告展示完成后跳转到dcloud的启动activity
Intent intent = new Intent();
intent.setClass(SplashActivity.this, PandoraEntry.class);
startActivity(intent);
}
3-3、修改AndroidManifest.xml,设置SplashActivity为启动activity
<activity
android:name="com.example.H5PlusPlugin.SplashActivity"
android:configChanges="orientation|keyboardHidden|keyboard|navigation"
android:label="@string/app_name"
android:launchMode="singleTask"
android:hardwareAccelerated="true"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:screenOrientation="user"
android:windowSoftInputMode="adjustResize"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="io.dcloud.PandoraEntry"
android:configChanges="orientation|keyboardHidden|keyboard|navigation"
android:label="@string/app_name"
android:launchMode="singleTask"
android:hardwareAccelerated="true"
android:theme="@style/TranslucentTheme"
android:screenOrientation="user"
android:windowSoftInputMode="adjustResize" >
</activity>
到这里就完成了开屏广告了
4、新增banner2.0的activity
这里是通过一个取巧的办法实现的,腾讯广告联盟的广告要在activity里展示,而我们又修改不了dcloud的activity,所以就新建一个Dialog样式的activity,来展示在dcloud的activity上了
4-1、新建一个activity,先把DEMO里的UnifiedBannerActivity里面的代码拷过来(千万不要拷贝BannerActivity里的,我没看清楚banner2.0广告,结果浪费了几个小时调试......),然后修改
public static BannerActivity instance = null;//用于在H5里关闭该activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_banner);
getIAD().loadAD();
}
private String getPosID() {
return Constants.UNIFIED_INTERSTITIAL_ID_ONLY_SMALL;
}
public static void h5Finish() {
BannerActivity.instance.finish();
}
activity_unified_banner代码如下(显示在底部的banner)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="1000dp"
android:layout_height="55dp" >
<FrameLayout
android:id="@+id/bannerContainer"
android:layout_width="match_parent"
android:layout_height="150px"
android:layout_alignParentBottom="true" >
</FrameLayout>
</FrameLayout>
BannerActivity的样式代码如下
<resources>
<style name="Theme.Transparent" parent="android:Theme.Dialog">
<item name="android:windowFrame">@null</item><!-- 边框 -->
<item name="android:windowIsTranslucent">true</item><!--此对话框的背景-->
<item name="android:windowBackground">@drawable/bakground_circle</item><!--对话框是否透明-->
<item name="android:windowContentOverlay">@null</item><!--对话框是否有遮盖-->
<item name="android:windowNoTitle">true</item><!--对话框无标题-->
<item name="android:windowIsFloating">true</item> <!--对话框是否浮动-->
<item name="android:backgroundDimEnabled">false</item><!--是否允许对话框的背景变暗-->
</style>
</resources>
5、用h5通过native调用activity
5-1、打开activity
//加载banner广告
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
var intent = new Intent();
intent.setClassName(main, 'com.xx.xx.BannerActivity');//这里是Activity的路径
main.startActivity(intent);
//关闭banner广告
plus.android.invoke("com.xx.xx.BannerActivity", "h5Finish");
其他
插屏广告比较好插入,和banner广告一样就可以了,原生广告怎么搞还没想到办法,希望有能搞定的朋友可以补充一下。
附上项目实际应用的下载地址http://www.hongxun88.cn/download
摸索了几天终于采取一个不那么好的办法搞定了dcloud集成腾讯广告联盟,特记录下来,希望能给新手朋友一些帮助,安卓我只带过团队,自己也是第一次实际操作,老鸟请忽略。
1、离线打包
2、集成腾讯广告联盟的SDK
3、新增一个启动页
4、新增banner2.0的activity
5、用h5通过native调用activity
1、离线打包
这个官方有详细的介绍了
http://ask.dcloud.net.cn/article/508
说一下我踩过的几个坑
1-1、Module not specified
导入project,不是直接导入,而是先随意新建一个project,然后导入module,否则运行的时候会报错
1-2、Android Studio报错Manifest merger failed with multiple errors
这个提示是因为AndroidManifest.xml中的配置和build.gradle里的配置不一样,手动将build.gradle里的applicationId改成和AndroidManifest.xml的一致就可以正常运行了
2、集成腾讯广告联盟的SDK
2-1、将腾讯广告联盟的jar文件拷贝到项目根目录的libs目录下,
2-2、然后修改build.gradle,dependencies的最后一行加上implementation files('libs/GDTSDK.tbs.4.30.906.jar')(GDTSDK.tbs.4.30.906.jar是刚拷贝的jar的名字)
2-3、修改AndroidMnifest.xml(腾讯广告联盟的文档有描述),就不详细写了
3、新增一个启动activity
3-1、新建一个activity作为启动activity
3-2、启动activity参照腾讯广告联盟的DEMO就可以了,代码略作修改,这里加了一个限制,开屏广告一个小时只展示一次
protected void onCreate(@Nullable Bundle savedInstanceState) {
Long curDate = new Date().getTime();//当前时间
//获取上次时间
SharedPreferences sp = getSharedPreferences("sp_name", Context.MODE_PRIVATE);
String lastSpADTime = sp.getString("lastSpADTime", "0");
Long lastSpADTimeLong = Long.parseLong(lastSpADTime);
if(curDate - lastSpADTimeLong > 3600000) {//超过一个小时则再次显示广告
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
container = (ViewGroup) this.findViewById(R.id.splash_container);
skipView = (TextView) findViewById(R.id.skip_view);
splashHolder = (ImageView) findViewById(R.id.splash_holder);
splashAD = new SplashAD(this, container, skipView, Constants.APPID, getPosId(), this, 0);
//写入上次时间
SharedPreferences.Editor editor = sp.edit();
editor.putString("lastSpADTime", curDate.toString());
editor.apply();
} else {
this.onADDismissed();
}
}
private String getPosId() {
return Constants.SplashPosID;
}
public void onADDismissed() {
this.finish();
//主要改动是在这里,开屏广告展示完成后跳转到dcloud的启动activity
Intent intent = new Intent();
intent.setClass(SplashActivity.this, PandoraEntry.class);
startActivity(intent);
}
3-3、修改AndroidManifest.xml,设置SplashActivity为启动activity
<activity
android:name="com.example.H5PlusPlugin.SplashActivity"
android:configChanges="orientation|keyboardHidden|keyboard|navigation"
android:label="@string/app_name"
android:launchMode="singleTask"
android:hardwareAccelerated="true"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:screenOrientation="user"
android:windowSoftInputMode="adjustResize"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="io.dcloud.PandoraEntry"
android:configChanges="orientation|keyboardHidden|keyboard|navigation"
android:label="@string/app_name"
android:launchMode="singleTask"
android:hardwareAccelerated="true"
android:theme="@style/TranslucentTheme"
android:screenOrientation="user"
android:windowSoftInputMode="adjustResize" >
</activity>
到这里就完成了开屏广告了
4、新增banner2.0的activity
这里是通过一个取巧的办法实现的,腾讯广告联盟的广告要在activity里展示,而我们又修改不了dcloud的activity,所以就新建一个Dialog样式的activity,来展示在dcloud的activity上了
4-1、新建一个activity,先把DEMO里的UnifiedBannerActivity里面的代码拷过来(千万不要拷贝BannerActivity里的,我没看清楚banner2.0广告,结果浪费了几个小时调试......),然后修改
public static BannerActivity instance = null;//用于在H5里关闭该activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_banner);
getIAD().loadAD();
}
private String getPosID() {
return Constants.UNIFIED_INTERSTITIAL_ID_ONLY_SMALL;
}
public static void h5Finish() {
BannerActivity.instance.finish();
}
activity_unified_banner代码如下(显示在底部的banner)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="1000dp"
android:layout_height="55dp" >
<FrameLayout
android:id="@+id/bannerContainer"
android:layout_width="match_parent"
android:layout_height="150px"
android:layout_alignParentBottom="true" >
</FrameLayout>
</FrameLayout>
BannerActivity的样式代码如下
<resources>
<style name="Theme.Transparent" parent="android:Theme.Dialog">
<item name="android:windowFrame">@null</item><!-- 边框 -->
<item name="android:windowIsTranslucent">true</item><!--此对话框的背景-->
<item name="android:windowBackground">@drawable/bakground_circle</item><!--对话框是否透明-->
<item name="android:windowContentOverlay">@null</item><!--对话框是否有遮盖-->
<item name="android:windowNoTitle">true</item><!--对话框无标题-->
<item name="android:windowIsFloating">true</item> <!--对话框是否浮动-->
<item name="android:backgroundDimEnabled">false</item><!--是否允许对话框的背景变暗-->
</style>
</resources>
5、用h5通过native调用activity
5-1、打开activity
//加载banner广告
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
var intent = new Intent();
intent.setClassName(main, 'com.xx.xx.BannerActivity');//这里是Activity的路径
main.startActivity(intent);
//关闭banner广告
plus.android.invoke("com.xx.xx.BannerActivity", "h5Finish");
其他
插屏广告比较好插入,和banner广告一样就可以了,原生广告怎么搞还没想到办法,希望有能搞定的朋友可以补充一下。
附上项目实际应用的下载地址http://www.hongxun88.cn/download