HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

接单,iOS+Android原生插件开发,价格美丽

Android iOS 插件开发

接单,iOS+Android原生插件开发,价格美丽,也有现成的插件

QQ:1037606624

接单,iOS+Android原生插件开发,价格美丽,也有现成的插件

QQ:1037606624

html2canvas截屏并保存到手机相册

截屏
<div ref="imageWrapper">  
   <p>要截屏的内容</p>  
</div>
// import html2canvas from "html2canvas"; // 当前vue文件引入html2canvas  
// components: {html2canvas}  

 // 点击保存图片  
    justDoIt() {  
      var that = this;  
      if (navigator.userAgent.indexOf("Html5Plus") >= 0) {  
        that.saveCodeBtnHide(1);  
        // 5+app环境  
        console.log("点击保存图片");  
        that.$nextTick(() => {  
          that.toImage();  
        });  
      }  
    },  
    // 网页截图  
    toImage() {  
      var that = this;  
      setTimeout(() => {  
        html2canvas(this.$refs.imageWrapper, {  
          backgroundColor: null,  
          useCORS: true, // 开启跨域配置  
          allowTaint: true, // 允许跨域图片  
          taintTest: true // 是否在渲染前测试图片  
        }).then(canvas => {  
          let dataURL = canvas.toDataURL("image/png");  
          console.log("网页截图");  
          //   console.log(dataURL);  
          that.savePicture(dataURL);  
        });  
      }, 300);  
    },  
    // 保存图片到相册中  
    savePicture(imgurl) {  
      var that = this;  
      var b = new plus.nativeObj.Bitmap("bitblmap");  
      console.log("☆☆☆☆☆☆ 保存图片到相册中");  
      console.log(b);  
      b.loadBase64Data(  
        imgurl,  
        function() {  
          console.log("图片创建成功");  
          var fileName = "_doc/img1.png";  
          b.save(  
            fileName,  
            { overwrite: true },  
            object => {  
              plus.gallery.save(  
                fileName,  
                () => {  
                  console.log("保存图片到相册成功");  
                },  
                () => {  
                  console.log("保存图片到相册失败");  
                }  
              );  
            },  
            () => {  
              console.log("保存失败");  
            }  
          );  
        },  
        function() {  
          console.log("图片创建失败");  
        }  
      );  
    }
继续阅读 »
<div ref="imageWrapper">  
   <p>要截屏的内容</p>  
</div>
// import html2canvas from "html2canvas"; // 当前vue文件引入html2canvas  
// components: {html2canvas}  

 // 点击保存图片  
    justDoIt() {  
      var that = this;  
      if (navigator.userAgent.indexOf("Html5Plus") >= 0) {  
        that.saveCodeBtnHide(1);  
        // 5+app环境  
        console.log("点击保存图片");  
        that.$nextTick(() => {  
          that.toImage();  
        });  
      }  
    },  
    // 网页截图  
    toImage() {  
      var that = this;  
      setTimeout(() => {  
        html2canvas(this.$refs.imageWrapper, {  
          backgroundColor: null,  
          useCORS: true, // 开启跨域配置  
          allowTaint: true, // 允许跨域图片  
          taintTest: true // 是否在渲染前测试图片  
        }).then(canvas => {  
          let dataURL = canvas.toDataURL("image/png");  
          console.log("网页截图");  
          //   console.log(dataURL);  
          that.savePicture(dataURL);  
        });  
      }, 300);  
    },  
    // 保存图片到相册中  
    savePicture(imgurl) {  
      var that = this;  
      var b = new plus.nativeObj.Bitmap("bitblmap");  
      console.log("☆☆☆☆☆☆ 保存图片到相册中");  
      console.log(b);  
      b.loadBase64Data(  
        imgurl,  
        function() {  
          console.log("图片创建成功");  
          var fileName = "_doc/img1.png";  
          b.save(  
            fileName,  
            { overwrite: true },  
            object => {  
              plus.gallery.save(  
                fileName,  
                () => {  
                  console.log("保存图片到相册成功");  
                },  
                () => {  
                  console.log("保存图片到相册失败");  
                }  
              );  
            },  
            () => {  
              console.log("保存失败");  
            }  
          );  
        },  
        function() {  
          console.log("图片创建失败");  
        }  
      );  
    }
收起阅读 »

android 离线打包,video组件提示未勾选videoPlayer模块

VideoPlayer App离线打包

android离线打包,路途非常曲折,首次尝试,会出现各种问题。
首先,参照官网给的离线打包文档(Android平台App本地离线打包),一定要按照官网文档上写的来做,不要自由发挥,否则都是坑。。


build.gradle中compileSdkVersion写30会白屏(Android版本10.0),换用下面的配置就好了。。

android {  
  compileSdkVersion 28  
  defaultConfig {  
      applicationId "com.example.myapplication"  
      minSdkVersion 19  
      targetSdkVersion 28  
      versionCode 1  
      versionName "1.0"  
      multiDexEnabled true  
  }

其次,如果打包带有vedio组件,要在manifest.json中勾选videoPlayer选项。并且需要使用官方的云打包才能正常播放视频。
如果要离线打包,即使manifest.json已做了video的配置,运行仍然会报模块未配置的错。官方说是需要自己在工程中配置,但具体如何配置,仍未找到相关说明。
希望官方能给出明确的离线打包,video配置相关说明,既然要做成开源的,就不要总是往付费方向引导。

继续阅读 »

android离线打包,路途非常曲折,首次尝试,会出现各种问题。
首先,参照官网给的离线打包文档(Android平台App本地离线打包),一定要按照官网文档上写的来做,不要自由发挥,否则都是坑。。


build.gradle中compileSdkVersion写30会白屏(Android版本10.0),换用下面的配置就好了。。

android {  
  compileSdkVersion 28  
  defaultConfig {  
      applicationId "com.example.myapplication"  
      minSdkVersion 19  
      targetSdkVersion 28  
      versionCode 1  
      versionName "1.0"  
      multiDexEnabled true  
  }

其次,如果打包带有vedio组件,要在manifest.json中勾选videoPlayer选项。并且需要使用官方的云打包才能正常播放视频。
如果要离线打包,即使manifest.json已做了video的配置,运行仍然会报模块未配置的错。官方说是需要自己在工程中配置,但具体如何配置,仍未找到相关说明。
希望官方能给出明确的离线打包,video配置相关说明,既然要做成开源的,就不要总是往付费方向引导。

收起阅读 »

uni小程序SDK Module调用问题

class LoginModule : WXModule() {

@JSMethod  
fun login(data: JsonObject, mCallback: JSCallback) {  
    mCallback.invoke("OK")  
}  

}

testFun() {
loginModule.login(params,
(ret) => {
console.log(ret)
this.setNativeMsg(ret)
})
}

控制台提示

console: [ERROR]TypeError: undefined is not an object (evaluating 'o.login')

继续阅读 »

class LoginModule : WXModule() {

@JSMethod  
fun login(data: JsonObject, mCallback: JSCallback) {  
    mCallback.invoke("OK")  
}  

}

testFun() {
loginModule.login(params,
(ret) => {
console.log(ret)
this.setNativeMsg(ret)
})
}

控制台提示

console: [ERROR]TypeError: undefined is not an object (evaluating 'o.login')

收起阅读 »

微服务下基于sleuth的参数透传功能探索

  1. 需求
    微服务环境,有A,B,C,D四个服务,调用关系为:A->B->C->D。用户在A的页面选择当前“语言”环境为“英文”,在某些业务场景下,其它几个服务需获取到这个“语言”信息。

  2. 分析
    这个需求还是很简单的,类似于“击鼓传花”:当前服务从上一个服务中获取参数,并传给下一个服务。个人感觉基本上所有的RPC框架都会遇到这个问题,只是以前SOA架构下,服务层级比较少,将“语言”、“登陆”等附加信息放在参数列表中并不会带来太多工作量,所以这个问题并不是太突出。而引入了微服务架构思想后,服务调用层级急剧增长,这就需要一个更加优雅的方式来解决附加信息的传递问题。

3.方案探索
3.1 方案一:参数放在接口参数列表中
3.1.1 优点:
思路简单,开发没有学习成本

3.1.2 缺点:
代码高度耦合:附加信息却要每个接口都显式维护
升级困难:如果将来再加一个参数,所有层级的接都要改动
引起迷惑:如果B服务的逻辑不需要“语言“参数,但是因为D需要,它也必须维护
太傻了,Big不够
3.1.3 思考:
微服务之间绝大多数情况是通过HTTP调用的,HTTP的header中也可以放参数信息。这样,接口参数中就不用维护这些附加信了。

3.2 方案二:参数放在httpRequest的header中
3.2.1 实现:
自定义一个Filter,获取Request中自己需要的附加信息
将这些信息放入ThreadLocal中
实现feign.Client(这里先忽略RestTemplate)的execute()方法,将附件信息在调用下一层服务前塞入request的header中
3.2.2 优点:
参数解耦

3.2.3 缺点:
如果B在获取到附加信息后,新起了一个线程”T1“来调用服务C,这时T1就无法从ThreadLocal拿到附加信息了

3.2.4 思考:
如果我知道怎么用无侵入的方式,在当前线程”T”创建子孙线程”T1”、”T1-1”时,将数据传给后代,就能解决这个问题了
微服务调用链框架Sleuth的核心功能即是跟踪一次请求从A到D的全过程,它肯定支持多线程调用下的traceId的传递。因此,我可以复用Sleuth的相关功能夹带私货
3.3 方案三:修改Sleuth源码,将附加信息跟着TraceId一起往后传递
3.3.1 优点:
原理简单,不用考虑底层实现
不用考虑兼容性等问题,Sleuth都已经实现好
快(对,就是这一个字)
3.3.2 缺点:
维护困难,很容易忘记以前修改了哪些地方,更别提移交给别人维护了
升级困难,以后每次Spring或者Sleuth升级,都要重新下载源码修改
3.3.3 思考:
目前获取参数的问题解决了,用Filter,只剩下保存并传给下一层的问题
既然Sleuth已经解决了多线程下traceId的传递问题,那我就直接用traceId来解决我的问题
3.4 方案四:充分利用traceId
3.4.1 实现:
自定义Filter(优先级要低于TraceFilter,因为你要获取TraceFilter里的traceId),拿到traceId和附加信息后,将它们存在本地缓存中,traceId为key,附加信息为value
参考方案二的实现3。重写execute()方法,获取当前线程的traceId(这个Sleuth有接口,不再介绍),然后再通过traceId去本地缓存中拿到附加信息,放进Request的header中
3.4.2 优点:
拥有上述方案所有的优点
解决上述方案所有缺点
3.4.3 缺点:http://springcloud.cn/view/41

继续阅读 »
  1. 需求
    微服务环境,有A,B,C,D四个服务,调用关系为:A->B->C->D。用户在A的页面选择当前“语言”环境为“英文”,在某些业务场景下,其它几个服务需获取到这个“语言”信息。

  2. 分析
    这个需求还是很简单的,类似于“击鼓传花”:当前服务从上一个服务中获取参数,并传给下一个服务。个人感觉基本上所有的RPC框架都会遇到这个问题,只是以前SOA架构下,服务层级比较少,将“语言”、“登陆”等附加信息放在参数列表中并不会带来太多工作量,所以这个问题并不是太突出。而引入了微服务架构思想后,服务调用层级急剧增长,这就需要一个更加优雅的方式来解决附加信息的传递问题。

3.方案探索
3.1 方案一:参数放在接口参数列表中
3.1.1 优点:
思路简单,开发没有学习成本

3.1.2 缺点:
代码高度耦合:附加信息却要每个接口都显式维护
升级困难:如果将来再加一个参数,所有层级的接都要改动
引起迷惑:如果B服务的逻辑不需要“语言“参数,但是因为D需要,它也必须维护
太傻了,Big不够
3.1.3 思考:
微服务之间绝大多数情况是通过HTTP调用的,HTTP的header中也可以放参数信息。这样,接口参数中就不用维护这些附加信了。

3.2 方案二:参数放在httpRequest的header中
3.2.1 实现:
自定义一个Filter,获取Request中自己需要的附加信息
将这些信息放入ThreadLocal中
实现feign.Client(这里先忽略RestTemplate)的execute()方法,将附件信息在调用下一层服务前塞入request的header中
3.2.2 优点:
参数解耦

3.2.3 缺点:
如果B在获取到附加信息后,新起了一个线程”T1“来调用服务C,这时T1就无法从ThreadLocal拿到附加信息了

3.2.4 思考:
如果我知道怎么用无侵入的方式,在当前线程”T”创建子孙线程”T1”、”T1-1”时,将数据传给后代,就能解决这个问题了
微服务调用链框架Sleuth的核心功能即是跟踪一次请求从A到D的全过程,它肯定支持多线程调用下的traceId的传递。因此,我可以复用Sleuth的相关功能夹带私货
3.3 方案三:修改Sleuth源码,将附加信息跟着TraceId一起往后传递
3.3.1 优点:
原理简单,不用考虑底层实现
不用考虑兼容性等问题,Sleuth都已经实现好
快(对,就是这一个字)
3.3.2 缺点:
维护困难,很容易忘记以前修改了哪些地方,更别提移交给别人维护了
升级困难,以后每次Spring或者Sleuth升级,都要重新下载源码修改
3.3.3 思考:
目前获取参数的问题解决了,用Filter,只剩下保存并传给下一层的问题
既然Sleuth已经解决了多线程下traceId的传递问题,那我就直接用traceId来解决我的问题
3.4 方案四:充分利用traceId
3.4.1 实现:
自定义Filter(优先级要低于TraceFilter,因为你要获取TraceFilter里的traceId),拿到traceId和附加信息后,将它们存在本地缓存中,traceId为key,附加信息为value
参考方案二的实现3。重写execute()方法,获取当前线程的traceId(这个Sleuth有接口,不再介绍),然后再通过traceId去本地缓存中拿到附加信息,放进Request的header中
3.4.2 优点:
拥有上述方案所有的优点
解决上述方案所有缺点
3.4.3 缺点:http://springcloud.cn/view/41

收起阅读 »

flex-direction row在v-for命令下不生效

uni-app新手,请教大神们一个问题,我想在一个view中添加 25个子view(5行5列),父view属性设置如下:
.game-area{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
子View属性设置:
.light-block{
width: 100rpx;
height: 100rpx;
}
模板如下:

<view class="game-area" v-for="(light, index) in lights" :key = "index">  
    <view class="light-block"></view>  
</view>

lights是一个有25个对象元素的数组。

显示后25个view排成了一列,row属性不起任何作用。如果不用v-for指令,手动添加,是没有问题的。这是为什么,有什么解决方案吗,先行谢过!

继续阅读 »

uni-app新手,请教大神们一个问题,我想在一个view中添加 25个子view(5行5列),父view属性设置如下:
.game-area{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
子View属性设置:
.light-block{
width: 100rpx;
height: 100rpx;
}
模板如下:

<view class="game-area" v-for="(light, index) in lights" :key = "index">  
    <view class="light-block"></view>  
</view>

lights是一个有25个对象元素的数组。

显示后25个view排成了一列,row属性不起任何作用。如果不用v-for指令,手动添加,是没有问题的。这是为什么,有什么解决方案吗,先行谢过!

收起阅读 »

你是否对uni-app跨端三端的v-slot存在疑惑,封装组建的必备神器啊~

scroll_view
 在原生的微信小程序中我的slot攻无不克、战无不胜。到了uni-app上由于跨端需求,这也出问题那也出问题,就h5稳定些,这大概还是vue的功劳吧,略略略~  

在一些特定组件的封装上,slot是无上神器,毕竟插槽大家都懂的,就自己那点技术能开发出什么大应用呢?性能啥的不在考虑范围内,方便、快捷、灵活、偷懒才是我们的第一选择,至于卡了,等用户碰到到再说吧(如果不封装,每次更新有改动,一改就是几十处,出错的概率更大。封装为组件,牵一发而动全军的感觉真好)。
好吧,我编不下去了,第一次发布插件,求指教。(功能可以正常运行,但是害怕,自己错了,还不知道错在哪~欢迎指教),在uni-app中,v-if和v-show是一种比较神奇的存在。
https://ext.dcloud.net.cn/plugin?id=2279

继续阅读 »
 在原生的微信小程序中我的slot攻无不克、战无不胜。到了uni-app上由于跨端需求,这也出问题那也出问题,就h5稳定些,这大概还是vue的功劳吧,略略略~  

在一些特定组件的封装上,slot是无上神器,毕竟插槽大家都懂的,就自己那点技术能开发出什么大应用呢?性能啥的不在考虑范围内,方便、快捷、灵活、偷懒才是我们的第一选择,至于卡了,等用户碰到到再说吧(如果不封装,每次更新有改动,一改就是几十处,出错的概率更大。封装为组件,牵一发而动全军的感觉真好)。
好吧,我编不下去了,第一次发布插件,求指教。(功能可以正常运行,但是害怕,自己错了,还不知道错在哪~欢迎指教),在uni-app中,v-if和v-show是一种比较神奇的存在。
https://ext.dcloud.net.cn/plugin?id=2279

收起阅读 »

建议把版本号增加到打包页面

新版本

建议把版本号增加到打包页面,选择打包的时候,直接可以填写版本号

建议把版本号增加到打包页面,选择打包的时候,直接可以填写版本号

插件市场是不是招不到人审核了,什么插件都往上放,要付费直接标明可好,打着开源浪费参考人时间

插件市场是不是招不到人审核了,什么插件都往上放,要付费直接标明可好,打着开源浪费参考人时间

插件市场是不是招不到人审核了,什么插件都往上放,要付费直接标明可好,打着开源浪费参考人时间

【uni-app实战-分享01】uni-app微信公众号授权登录,特别是vue模式的坑

uniapp 教程

用uni-app的朋友们都知道,uni-app是用vue开发的,那么有2种页面展现方式。

方式1:history,方式2:hash。hash模式带了个#号,而且发布到手机上,页面不能刷新,一刷新就404了。没办法,只能是选history模式。

下面说下3点注意事项:

1、保留登录前的页面参数。为了不让参数传到后台,并且在微信授权链接带来带去,可以将参数和登录前的地址存到本地缓存,代码如下:

let pages = getCurrentPages();  

//如果不是登录页  

if ("pages/login/login" != currentPage.route) {  

//保存登录前的地址  

        uni.setStorageSync("currentPage", currentPage.route);  

        //保存登录前的参数  

        uni.setStorageSync("currentPageOptions", currentPage.options);  

}

2、后端代码。基本没什么好讲的,就是一个跳过去授权,然后回调。回调的话填uni-app的登录成功地址,写入缓存。

// 存入登录信息  

uni.setStorageSync('token', options.token);  

uni.setStorageSync('user_id', options.user_id);  

// 获取登录前页面  

let url = '/' + uni.getStorageSync('currentPage');  

// 获取登录前参数  

let pageOptions = uni.getStorageSync('currentPageOptions');  

if(Object.keys(pageOptions).length > 0){  

      url += '?';  

     for(let i in pageOptions){  

            url += i + '=' + pageOptions[i] + '&';  

     }  

     url = url.substring(0, url.length - 1);  

}  

// 重载页面  

uni.reLaunch({  

       url: url  

});

3、配置路由跳转,以nginx为例,否则访问不到。比如打包后的代码放在h5目录下,则按以下设置:

location /h5 {  

try_files $uri $uri/ @router;  

}  

location @router {  

         rewrite ^.*$ /h5/index.html last;  

}

经过以上3点设置,登录前的参数和页面能够保留和跳转,发布到手机端都能正常登录访问。

喜欢的朋友点个关注,全是实战干货。

继续阅读 »

用uni-app的朋友们都知道,uni-app是用vue开发的,那么有2种页面展现方式。

方式1:history,方式2:hash。hash模式带了个#号,而且发布到手机上,页面不能刷新,一刷新就404了。没办法,只能是选history模式。

下面说下3点注意事项:

1、保留登录前的页面参数。为了不让参数传到后台,并且在微信授权链接带来带去,可以将参数和登录前的地址存到本地缓存,代码如下:

let pages = getCurrentPages();  

//如果不是登录页  

if ("pages/login/login" != currentPage.route) {  

//保存登录前的地址  

        uni.setStorageSync("currentPage", currentPage.route);  

        //保存登录前的参数  

        uni.setStorageSync("currentPageOptions", currentPage.options);  

}

2、后端代码。基本没什么好讲的,就是一个跳过去授权,然后回调。回调的话填uni-app的登录成功地址,写入缓存。

// 存入登录信息  

uni.setStorageSync('token', options.token);  

uni.setStorageSync('user_id', options.user_id);  

// 获取登录前页面  

let url = '/' + uni.getStorageSync('currentPage');  

// 获取登录前参数  

let pageOptions = uni.getStorageSync('currentPageOptions');  

if(Object.keys(pageOptions).length > 0){  

      url += '?';  

     for(let i in pageOptions){  

            url += i + '=' + pageOptions[i] + '&';  

     }  

     url = url.substring(0, url.length - 1);  

}  

// 重载页面  

uni.reLaunch({  

       url: url  

});

3、配置路由跳转,以nginx为例,否则访问不到。比如打包后的代码放在h5目录下,则按以下设置:

location /h5 {  

try_files $uri $uri/ @router;  

}  

location @router {  

         rewrite ^.*$ /h5/index.html last;  

}

经过以上3点设置,登录前的参数和页面能够保留和跳转,发布到手机端都能正常登录访问。

喜欢的朋友点个关注,全是实战干货。

收起阅读 »

IOS开发和发布证书申请流程

查看附件

查看附件

android云打包启动图错误:Execution failed for task ':app:mergeReleaseResources'.

.9.png

问题描述:

uniApp中设置了安卓9.png格式的启动图片以后,进行安卓APP云打包出现错误,错误日志:

FAILURE: Build failed with an exception.  

* What went wrong:  
Execution failed for task ':app:mergeReleaseResources'.  
> java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: Android resource compilation failed  
Output: error: top-left corner pixel must be either opaque white or transparent.  

......(此处省略更多)......

出现问题的原因及解决办法:

使用draw9patch工具制作保存出来的.9.png图片是包含着黑边的,该黑边本就用于指定哪些部分可以被拉伸填满容器,哪些部分保持不变,如果像这篇文章《androidUI设计 .9.png 制作及去黑线》,最后介绍的使用xUltimate-d9pc-x86工具去除黑边后,那打包就出现错误了,黑边是Android的.9.png图片实现自适应的核心,因此不能去除。

所以,使用draw9patch工具制作保存出来的.9.png启动图片,就直接使用了,不用处理掉黑边。

注:draw9patch工具制作保存出来的.9.png启动图片尺寸会比原图多1-2px,这不影响使用。(若有帮助请点个赞,本人也是在这个坑里吃了不少苦,为了能帮助到其它人,特意写了这个经验)

继续阅读 »

问题描述:

uniApp中设置了安卓9.png格式的启动图片以后,进行安卓APP云打包出现错误,错误日志:

FAILURE: Build failed with an exception.  

* What went wrong:  
Execution failed for task ':app:mergeReleaseResources'.  
> java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: Android resource compilation failed  
Output: error: top-left corner pixel must be either opaque white or transparent.  

......(此处省略更多)......

出现问题的原因及解决办法:

使用draw9patch工具制作保存出来的.9.png图片是包含着黑边的,该黑边本就用于指定哪些部分可以被拉伸填满容器,哪些部分保持不变,如果像这篇文章《androidUI设计 .9.png 制作及去黑线》,最后介绍的使用xUltimate-d9pc-x86工具去除黑边后,那打包就出现错误了,黑边是Android的.9.png图片实现自适应的核心,因此不能去除。

所以,使用draw9patch工具制作保存出来的.9.png启动图片,就直接使用了,不用处理掉黑边。

注:draw9patch工具制作保存出来的.9.png启动图片尺寸会比原图多1-2px,这不影响使用。(若有帮助请点个赞,本人也是在这个坑里吃了不少苦,为了能帮助到其它人,特意写了这个经验)

收起阅读 »