HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

5+app调用第三方地图导航 android版

/**  
     * 调用第三方导航  高德优先  百度  
     * @param lon  
     * @param lat  
     * @returns {boolean}  
     */  
    // com.baidu.BaiduMap  

    // com.autonavi.minimap  

    function dh(lon,lat){  

        if(plus.runtime.isApplicationExist({pname:'com.autonavi.minimap'})){  
                //用户已安装高德地图  
                plus.runtime.openURL('androidamap://navi?sourceApplication=com.knssshy.sj&lat='+lat+'&lon='+lon+'&dev=0',function(e) {  
                    plus.nativeUI.confirm( "检查到您未安装\"高德地图\".");  
                } );  
            }else if(plus.runtime.isApplicationExist({pname:'com.baidu.BaiduMap'})){  
                //用户已安装百度地图  
                plus.runtime.openURL('bdapp://map/direction?destination='+lat+','+lon+'&coord_type=gcj02&mode=driving&src=com.knssshy.sj',function(e) {  
                    plus.nativeUI.confirm( "检查到您未安装\"百度地图\".");  
                } );  
            }else{  
                alert('你没有安装导航软件(高德/百度).')  
            }  
    }

在JS中直接调用函数dh(lon,lat)就能打开第三方地图进行导航了,lon lat为坐标值。

继续阅读 »
/**  
     * 调用第三方导航  高德优先  百度  
     * @param lon  
     * @param lat  
     * @returns {boolean}  
     */  
    // com.baidu.BaiduMap  

    // com.autonavi.minimap  

    function dh(lon,lat){  

        if(plus.runtime.isApplicationExist({pname:'com.autonavi.minimap'})){  
                //用户已安装高德地图  
                plus.runtime.openURL('androidamap://navi?sourceApplication=com.knssshy.sj&lat='+lat+'&lon='+lon+'&dev=0',function(e) {  
                    plus.nativeUI.confirm( "检查到您未安装\"高德地图\".");  
                } );  
            }else if(plus.runtime.isApplicationExist({pname:'com.baidu.BaiduMap'})){  
                //用户已安装百度地图  
                plus.runtime.openURL('bdapp://map/direction?destination='+lat+','+lon+'&coord_type=gcj02&mode=driving&src=com.knssshy.sj',function(e) {  
                    plus.nativeUI.confirm( "检查到您未安装\"百度地图\".");  
                } );  
            }else{  
                alert('你没有安装导航软件(高德/百度).')  
            }  
    }

在JS中直接调用函数dh(lon,lat)就能打开第三方地图进行导航了,lon lat为坐标值。

收起阅读 »

在uniapp h5中在线引入高德地图js api的方法分享

高德文档:https://lbs.amap.com/api/javascript-api/guide/abc/load
查询了好久都没有找到解决方法,弄好了分享一下.

//这里要加window., loadScrpit的callback才会执行  
window.mapInit = function(){  
  let mapObj = new AMap.Map('iCenter');  
  mapObj.plugin('AMap.Geolocation', function () {  
      let geolocation = new AMap.Geolocation({  
          enableHighAccuracy: false,//是否使用高精度定位,默认:true  
          timeout: 5000,          //超过5秒后停止定位,默认:无穷大  
      });  
      mapObj.addControl(geolocation);  
      geolocation.getCurrentPosition();  
      //返回定位信息  
      AMap.event.addListener(geolocation, 'complete', function (res) {  
          console.log(res);  
      });  
      //返回定位出错信息  
      AMap.event.addListener(geolocation, 'error', function (err) {  
          console.log(err);  
      });  
  });  
}  
// 页面onload调用此方法  
function loadScrpit(){  
  var script = document.createElement('script');  
  script.src = "https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值&callback=mapInit";  
  document.body.appendChild(script);  
}
继续阅读 »

高德文档:https://lbs.amap.com/api/javascript-api/guide/abc/load
查询了好久都没有找到解决方法,弄好了分享一下.

//这里要加window., loadScrpit的callback才会执行  
window.mapInit = function(){  
  let mapObj = new AMap.Map('iCenter');  
  mapObj.plugin('AMap.Geolocation', function () {  
      let geolocation = new AMap.Geolocation({  
          enableHighAccuracy: false,//是否使用高精度定位,默认:true  
          timeout: 5000,          //超过5秒后停止定位,默认:无穷大  
      });  
      mapObj.addControl(geolocation);  
      geolocation.getCurrentPosition();  
      //返回定位信息  
      AMap.event.addListener(geolocation, 'complete', function (res) {  
          console.log(res);  
      });  
      //返回定位出错信息  
      AMap.event.addListener(geolocation, 'error', function (err) {  
          console.log(err);  
      });  
  });  
}  
// 页面onload调用此方法  
function loadScrpit(){  
  var script = document.createElement('script');  
  script.src = "https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值&callback=mapInit";  
  document.body.appendChild(script);  
}
收起阅读 »

扫码黑屏

Barcode

扫码黑屏这个问题一直在华为和小米等手机不定时出现。

1、先解决办法如下。在退出的时候释放扫码对象并关闭

     mui.init({  
                beforeback: function() {  
                    //返回true继续页面关闭逻辑  
                    if(scan != null) {  
                        scan.close()  
                        scan = null;  
                    }  
                    return true;  
                }  
     })

2、没有使用demo的用法,这里在mui.plusReady中使用setTimeOut 300之后初始化扫码

            var scan=null;  
            mui.plusReady(function() {  
                setTimeout("scanInit()", 300)  
            })  

            function scanInit() {  
                var filter = [plus.barcode.CODE128];  
                scan = new plus.barcode.Barcode('bcid', filter);  
                scan.onmarked = onmarked;  
                scan.onerror = onerror;  
                scan.start();  
            }

以上用了之后确实没有出现过黑屏

继续阅读 »

扫码黑屏这个问题一直在华为和小米等手机不定时出现。

1、先解决办法如下。在退出的时候释放扫码对象并关闭

     mui.init({  
                beforeback: function() {  
                    //返回true继续页面关闭逻辑  
                    if(scan != null) {  
                        scan.close()  
                        scan = null;  
                    }  
                    return true;  
                }  
     })

2、没有使用demo的用法,这里在mui.plusReady中使用setTimeOut 300之后初始化扫码

            var scan=null;  
            mui.plusReady(function() {  
                setTimeout("scanInit()", 300)  
            })  

            function scanInit() {  
                var filter = [plus.barcode.CODE128];  
                scan = new plus.barcode.Barcode('bcid', filter);  
                scan.onmarked = onmarked;  
                scan.onerror = onerror;  
                scan.start();  
            }

以上用了之后确实没有出现过黑屏

收起阅读 »

码灵程序员导航-一个帮助开发者成长的网址导航

uniapp 教程 5+App开发 App入门

> 作为一名码农,随着平时工作的需要,慢慢收集了国内外很多优秀相关程序员站点,这其中包括在线工具、在线运行、免费接口、在线资源、在线学习、技术论坛、技术博客等等,为广大用户提供学习网站、学习方向、学习途径等内容。

https://nav.imaring.com/

继续阅读 »

> 作为一名码农,随着平时工作的需要,慢慢收集了国内外很多优秀相关程序员站点,这其中包括在线工具、在线运行、免费接口、在线资源、在线学习、技术论坛、技术博客等等,为广大用户提供学习网站、学习方向、学习途径等内容。

https://nav.imaring.com/

收起阅读 »

uniapp发布到iOS Appstore被拒绝

iOS

We discovered that your app contains hidden features. Attempting to hide features, functionality or content in your app is considered egregious behavior and can lead to removal from the Apple Developer Program.

Specifically, we found that your app includes AliPay (支付寶), which provides access to external payment mechanisms and enables the purchase of content, services, or functionality by means other than the in-app purchase API.

If you feel that we have misunderstood how your app functions and that your app is compliant with the App Store Review Guidelines, please reply to this message in Resolution Center to explain how this feature works.

The next submission of this app may require a longer review time, and this app will not be eligible for an expedited review until this issue is resolved.

这个是发布到苹果Appstore的被拒绝的信息,说的是我在代码中使用了支付宝的sdk

问题排查:
1.uniapp可能封装了sdk,需要去检查是否打包的使用进行了引入;


很明显,没有勾选,说明不是这个问题导致的;
2.需要排查是不是打得iOS的ipa包里面包含了支付宝的信息,需要解压看下;
把ipa修改成zip,双击解压


会看到一个XXX.app的文件,右键该文件会看到“显示包内容”,点击即可


打开infoplist,会发现里面有过alipay,苹果多半是看到这个,给拒绝了


因为info.plist是iOS打包必须要有的,很多配置都是写在里面,我找了一下发现xbuild工具里面没有修改info.plist的地方,只能通过离线进行通过xcode打包了。
我先操作一下试试,看看这次修改了是否能通过审核,再来更新。

继续阅读 »

We discovered that your app contains hidden features. Attempting to hide features, functionality or content in your app is considered egregious behavior and can lead to removal from the Apple Developer Program.

Specifically, we found that your app includes AliPay (支付寶), which provides access to external payment mechanisms and enables the purchase of content, services, or functionality by means other than the in-app purchase API.

If you feel that we have misunderstood how your app functions and that your app is compliant with the App Store Review Guidelines, please reply to this message in Resolution Center to explain how this feature works.

The next submission of this app may require a longer review time, and this app will not be eligible for an expedited review until this issue is resolved.

这个是发布到苹果Appstore的被拒绝的信息,说的是我在代码中使用了支付宝的sdk

问题排查:
1.uniapp可能封装了sdk,需要去检查是否打包的使用进行了引入;


很明显,没有勾选,说明不是这个问题导致的;
2.需要排查是不是打得iOS的ipa包里面包含了支付宝的信息,需要解压看下;
把ipa修改成zip,双击解压


会看到一个XXX.app的文件,右键该文件会看到“显示包内容”,点击即可


打开infoplist,会发现里面有过alipay,苹果多半是看到这个,给拒绝了


因为info.plist是iOS打包必须要有的,很多配置都是写在里面,我找了一下发现xbuild工具里面没有修改info.plist的地方,只能通过离线进行通过xcode打包了。
我先操作一下试试,看看这次修改了是否能通过审核,再来更新。

收起阅读 »

关于Apple发布的 App Updates for HTML5 Apps 的说明

Appstore

2019年9月6日,Apple发布一份声明,原文见此:https://developer.apple.com/news/?id=09062019b

这份声明着重强调的是Appstore更新的4.7规定,即:

  • In June, we updated guideline 4.7 sections 4, 5, & 6, to further narrow these exceptions and clarify an existing restriction. Apps containing or running code that is not embedded in the binary cannot provide access to real money gaming, lotteries, or charitable donations, among other changes

翻译成中文是:

  • 6月,我们更新了指南4.7第4、5和6节,以进一步缩小这些例外的范围并阐明现有限制。包含或运行未嵌入二进制文件中的代码的应用程序无法访问真钱游戏,彩票或慈善捐款以及其他更改

Apple强调,新app必须符合此规定,否则不予上线。同时给予老app 6个月的宽限期,在2020年3月前完成更新改造,否则会下架。

现在已经2020年3月了,每天都有uni-app做的应用新上架Appstore,他们都符合新规定,包括官方的hello uni-app。

但是一些不明真相的人仍然在传谣,技术圈里也如此多谣言令我们很遗憾。

DCloud建议开发者始终明白Apple害怕什么、想要什么:
Apple害怕的是:

  1. 提供体验不佳的网页应用,与在Safari里访问没有区别
  2. 通过动态更新绕过Apple的政策(不管是违反了法律,涉及黄赌毒,还是虚拟商品未通过iap支付,绕开Apple的分成)
  3. 优质的app都在Android上,而iOS上无法上架,导致用户都跑去用Android去了

Apple想要的是:

  • 需要开发者提供优质应用,以吸引Apple的手机用户
  • 如果涉及虚拟支付,一定要让Apple分钱

只要你的app体验良好,Apple手机用户喜欢,不违法、不侵害Apple利益,Appstore不会拒绝你。

贸易战虽然起起伏伏,但Apple对中国的政策是很谨小慎微的。比如香港暴徒曝光警察位置的App,Google不肯下架,Apple主动下架,因为它不想在中国找事情,卖iPhone是最重要的。

另外,自从iOS13将uiwebview设为私有API,而wkWebview限制非常多,这导致老的5+App和wap2app体验受限,想提供优质体验的应用,建议开发者尽快升级为uni-app。
uni-app不是一个网页套壳应用,它的js根本不运行在webview里(所以也没有document等对象),也不受wkwebview的各种限制。而如果使用nvue的话,视图层也不在webview里,和html5一点关系都没有。

继续阅读 »

2019年9月6日,Apple发布一份声明,原文见此:https://developer.apple.com/news/?id=09062019b

这份声明着重强调的是Appstore更新的4.7规定,即:

  • In June, we updated guideline 4.7 sections 4, 5, & 6, to further narrow these exceptions and clarify an existing restriction. Apps containing or running code that is not embedded in the binary cannot provide access to real money gaming, lotteries, or charitable donations, among other changes

翻译成中文是:

  • 6月,我们更新了指南4.7第4、5和6节,以进一步缩小这些例外的范围并阐明现有限制。包含或运行未嵌入二进制文件中的代码的应用程序无法访问真钱游戏,彩票或慈善捐款以及其他更改

Apple强调,新app必须符合此规定,否则不予上线。同时给予老app 6个月的宽限期,在2020年3月前完成更新改造,否则会下架。

现在已经2020年3月了,每天都有uni-app做的应用新上架Appstore,他们都符合新规定,包括官方的hello uni-app。

但是一些不明真相的人仍然在传谣,技术圈里也如此多谣言令我们很遗憾。

DCloud建议开发者始终明白Apple害怕什么、想要什么:
Apple害怕的是:

  1. 提供体验不佳的网页应用,与在Safari里访问没有区别
  2. 通过动态更新绕过Apple的政策(不管是违反了法律,涉及黄赌毒,还是虚拟商品未通过iap支付,绕开Apple的分成)
  3. 优质的app都在Android上,而iOS上无法上架,导致用户都跑去用Android去了

Apple想要的是:

  • 需要开发者提供优质应用,以吸引Apple的手机用户
  • 如果涉及虚拟支付,一定要让Apple分钱

只要你的app体验良好,Apple手机用户喜欢,不违法、不侵害Apple利益,Appstore不会拒绝你。

贸易战虽然起起伏伏,但Apple对中国的政策是很谨小慎微的。比如香港暴徒曝光警察位置的App,Google不肯下架,Apple主动下架,因为它不想在中国找事情,卖iPhone是最重要的。

另外,自从iOS13将uiwebview设为私有API,而wkWebview限制非常多,这导致老的5+App和wap2app体验受限,想提供优质体验的应用,建议开发者尽快升级为uni-app。
uni-app不是一个网页套壳应用,它的js根本不运行在webview里(所以也没有document等对象),也不受wkwebview的各种限制。而如果使用nvue的话,视图层也不在webview里,和html5一点关系都没有。

收起阅读 »

app、h5上实现左滑、右滑返回上一页

右滑关闭

下面的代码是我自用的,等后面空了再做成组件。先以代码的形式分享。由于ios本身就自带了功能,所以ios的左右滑功能我给过滤掉了(需要的话可以自己修改代码)。

第一步:将代码保存为组件

下面是代码,可以定义为 pageFooter.vue,以我自己的为例,我将文件放到了@/components/common/pageFooter.vue
下面是代码:

<template>  
    <view v-if="platform != 'ios'">  
        <view class="left-side" @touchstart.stop="handleStart" @touchend.stop="handleEnd" v-if="leftDrag"></view>  
        <view class="right-side" @touchstart.stop="handleStart" @touchend.stop="handleEnd" v-if="rightDrag"></view>  
    </view>  
</template>  

<script>  
export default {  
    props: {  
        leftDrag: {  
            type: Boolean,  
            default: true  
        },  
        rightDrag: {  
            type: Boolean,  
            default: true  
        }  
    },  
    data() {  
        return {  
            startPosX: 0,  
            direction: 'left',  
            platform: uni.getSystemInfoSync().platform.toLowerCase(),  
            windowWidth: uni.getSystemInfoSync().windowWidth  
        };  
    },  
    methods: {  
        handleStart(e) {  
            if (!e.touches) {  
                return;  
            }  
            this.startPosX = e.touches[0].clientX;  
            this.direction = this.startPosX > this.windowWidth / 2 ? 'right' : 'left';  
        },  
        handleEnd(e) {  
            if (!e.changedTouches || !e.changedTouches[0]) {  
                return;  
            }  
            let pages = getCurrentPages(),  
                page = pages[pages.length - 1];  
            if (!page) {  
                return;  
            }  
            let x = e.changedTouches[0].clientX;  
            const offset = x - this.startPosX;  
            const canDrag = (this.direction == 'left' && offset >= 50) || (this.direction == 'right' && offset <= -50);  
            if (canDrag) {  
                this.startPosX = 0;  
                uni.navigateBack();  
            }  
        }  
    }  
};  
</script>  

<style lang="scss">  
@mixin pos {  
    position: fixed;  
    top: 0;  
    bottom: 0;  
    width: 40rpx;  
    opacity: 0.01;  
    background-color: $uni-bg-color;  
}  
.left-side {  
    @include pos;  
    left: 0;  
}  
.right-side {  
    @include pos;  
    right: 0;  
}  
</style>

第二步:在需要的地方引入组件也可以作为全局组件引入

全局组件引入方式

import pageFooter from '@/components/common/pageFooter.vue';  
Vue.component('pageFooter', pageFooter);

页面组件引入方式

<template>  
    <view>  
       <!-- your view code -->  
    </view>  
</template>  

<script>  
    import pageFooter from '@/components/common/pageFooter.vue';  
    export default {  
        components:{  
            pageFooter  
        }  
    }  
</script>  
<style></style>

第三步,在模板的最底部引用组件

<!-- this is you vue page -->  
<template>  
    <view>  
       <!-- your view code -->  

       <!-- leftDrag:开启右滑返回,rightDrag:开启左滑返回 -->  
       <pageFooter :leftDrag="true" :rightDrag="true"/>  
    </view>  
</template>  

<script>  
    import pageFooter from '@/components/common/pageFooter.vue';  
    export default {  
        components:{  
            pageFooter  
        }  
    }  
</script>  
<style></style>

注意事项

  1. 由于是页面的左右两侧开启了40rpx的宽度用来作为用户左右滑的事件触发层,因此在这个位置的点击或者其他事件会失效。我自己的运用由于左右两边的边距基本上都在30rpx,因此影响不大,这个触发点的宽度可以自己修改;
  2. 由于我自己的运用只有app和h5,因此小程序我没做测试。

不足之处

  1. 本来想做下左滑跟手操作——手滑到哪页面跟到哪,但是发现页面抖动的厉害,暂时没想到好的办法处理,希望高手分享下;
  2. 视频之类的页面有可能要用cover-view来做,不然在视频上面可能会失效。
继续阅读 »

下面的代码是我自用的,等后面空了再做成组件。先以代码的形式分享。由于ios本身就自带了功能,所以ios的左右滑功能我给过滤掉了(需要的话可以自己修改代码)。

第一步:将代码保存为组件

下面是代码,可以定义为 pageFooter.vue,以我自己的为例,我将文件放到了@/components/common/pageFooter.vue
下面是代码:

<template>  
    <view v-if="platform != 'ios'">  
        <view class="left-side" @touchstart.stop="handleStart" @touchend.stop="handleEnd" v-if="leftDrag"></view>  
        <view class="right-side" @touchstart.stop="handleStart" @touchend.stop="handleEnd" v-if="rightDrag"></view>  
    </view>  
</template>  

<script>  
export default {  
    props: {  
        leftDrag: {  
            type: Boolean,  
            default: true  
        },  
        rightDrag: {  
            type: Boolean,  
            default: true  
        }  
    },  
    data() {  
        return {  
            startPosX: 0,  
            direction: 'left',  
            platform: uni.getSystemInfoSync().platform.toLowerCase(),  
            windowWidth: uni.getSystemInfoSync().windowWidth  
        };  
    },  
    methods: {  
        handleStart(e) {  
            if (!e.touches) {  
                return;  
            }  
            this.startPosX = e.touches[0].clientX;  
            this.direction = this.startPosX > this.windowWidth / 2 ? 'right' : 'left';  
        },  
        handleEnd(e) {  
            if (!e.changedTouches || !e.changedTouches[0]) {  
                return;  
            }  
            let pages = getCurrentPages(),  
                page = pages[pages.length - 1];  
            if (!page) {  
                return;  
            }  
            let x = e.changedTouches[0].clientX;  
            const offset = x - this.startPosX;  
            const canDrag = (this.direction == 'left' && offset >= 50) || (this.direction == 'right' && offset <= -50);  
            if (canDrag) {  
                this.startPosX = 0;  
                uni.navigateBack();  
            }  
        }  
    }  
};  
</script>  

<style lang="scss">  
@mixin pos {  
    position: fixed;  
    top: 0;  
    bottom: 0;  
    width: 40rpx;  
    opacity: 0.01;  
    background-color: $uni-bg-color;  
}  
.left-side {  
    @include pos;  
    left: 0;  
}  
.right-side {  
    @include pos;  
    right: 0;  
}  
</style>

第二步:在需要的地方引入组件也可以作为全局组件引入

全局组件引入方式

import pageFooter from '@/components/common/pageFooter.vue';  
Vue.component('pageFooter', pageFooter);

页面组件引入方式

<template>  
    <view>  
       <!-- your view code -->  
    </view>  
</template>  

<script>  
    import pageFooter from '@/components/common/pageFooter.vue';  
    export default {  
        components:{  
            pageFooter  
        }  
    }  
</script>  
<style></style>

第三步,在模板的最底部引用组件

<!-- this is you vue page -->  
<template>  
    <view>  
       <!-- your view code -->  

       <!-- leftDrag:开启右滑返回,rightDrag:开启左滑返回 -->  
       <pageFooter :leftDrag="true" :rightDrag="true"/>  
    </view>  
</template>  

<script>  
    import pageFooter from '@/components/common/pageFooter.vue';  
    export default {  
        components:{  
            pageFooter  
        }  
    }  
</script>  
<style></style>

注意事项

  1. 由于是页面的左右两侧开启了40rpx的宽度用来作为用户左右滑的事件触发层,因此在这个位置的点击或者其他事件会失效。我自己的运用由于左右两边的边距基本上都在30rpx,因此影响不大,这个触发点的宽度可以自己修改;
  2. 由于我自己的运用只有app和h5,因此小程序我没做测试。

不足之处

  1. 本来想做下左滑跟手操作——手滑到哪页面跟到哪,但是发现页面抖动的厉害,暂时没想到好的办法处理,希望高手分享下;
  2. 视频之类的页面有可能要用cover-view来做,不然在视频上面可能会失效。
收起阅读 »

uni-app使用mpvue-echarts报this.echarts.setCanvasCreator is not a function的错误 的解决办法

echart

这个错误是由于 prors不能传递方法(之前是可以的,不知道是平台的差异还是版本的差异);
解决办法 将echarts.js 直接导入到echarts.vue 中.

import * as echarts from '@/common/js/echarts.simple.min';

还有uni api 有变动 echarts.vue 中有两处需要修改

createCanvasContext() 第二个参数传入当前组建 即this,
createSelectorQuery() 后面加上调用 in(this).

echarts.vue 完整代码如下

<template>  
  <canvas v-if="canvasId" class="ec-canvas" :id="canvasId" :canvasId="canvasId" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" @error="error"></canvas>  
</template>  

<script>  
import WxCanvas from './wx-canvas';  
import * as echarts from '@/common/js/echarts.simple.min';  

export default {  
  props: {  
    // echarts: {  
    //   required: true,  
    //   type: Object,  
    //   default() {  
    //     return echarts;  
    //   }  
    // },  
    onInit: {  
      required: true,  
      type: Function,  
      default: null  
    },  
    canvasId: {  
      type: String,  
      default: 'ec-canvas'  
    },  
    lazyLoad: {  
      type: Boolean,  
      default: false  
    },  
    disableTouch: {  
      type: Boolean,  
      default: false  
    },  
    throttleTouch: {  
      type: Boolean,  
      default: false  
    }  
  },  
  onReady() {  
    this.echarts = echarts;  

    if (!this.echarts) {  
      console.warn('组件需绑定 echarts 变量,例:<ec-canvas id="mychart-dom-bar" ' + 'canvas-id="mychart-bar" :echarts="echarts"></ec-canvas>');  
      return;  
    }  

    console.log('echarts');  
    console.log(this.onInit);  

    if (!this.lazyLoad) this.init();  
  },  
  methods: {  
    init() {  
      const version = wx.version.version.split('.').map(n => parseInt(n, 10));  
      const isValid = version[0] > 1 || (version[0] === 1 && version[1] > 9) || (version[0] === 1 && version[1] === 9 && version[2] >= 91);  
      if (!isValid) {  
        console.error('微信基础库版本过低,需大于等于 1.9.91。' + '参见:https://github.com/ecomfe/echarts-for-weixin' + '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');  
        return;  
      }  

      if (!this.onInit) {  
        console.warn('请传入 onInit 函数进行初始化');  
        return;  
      }  

      const canvasId = this.canvasId;  
      this.ctx = wx.createCanvasContext(canvasId,this);  

      const canvas = new WxCanvas(this.ctx, canvasId);  

      this.echarts.setCanvasCreator(() => canvas);  

      const query = wx.createSelectorQuery().in(this);  
      query  
        .select(`#${canvasId}`)  
        .boundingClientRect(res => {  
          if (!res) {  
            //setTimeout(() => this.init(), 200);  
            return;  
          }  

          this.chart = this.onInit(canvas, res.width, res.height);  
        })  
        .exec();  
    },  
    canvasToTempFilePath(opt) {  
      const { canvasId } = this;  
      this.ctx.draw(true, () => {  
        wx.canvasToTempFilePath({  
          canvasId,  
          ...opt  
        });  
      });  
    },  
    touchStart(e) {  
      const { disableTouch, chart } = this;  
      if (disableTouch || !chart || !e.mp.touches.length) return;  
      const touch = e.mp.touches[0];  
      chart._zr.handler.dispatch('mousedown', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
      chart._zr.handler.dispatch('mousemove', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
    },  
    touchMove(e) {  
      const { disableTouch, throttleTouch, chart, lastMoveTime } = this;  
      if (disableTouch || !chart || !e.mp.touches.length) return;  

      if (throttleTouch) {  
        const currMoveTime = Date.now();  
        if (currMoveTime - lastMoveTime < 240) return;  
        this.lastMoveTime = currMoveTime;  
      }  

      const touch = e.mp.touches[0];  
      chart._zr.handler.dispatch('mousemove', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
    },  
    touchEnd(e) {  
      const { disableTouch, chart } = this;  
      if (disableTouch || !chart) return;  
      const touch = e.mp.changedTouches ? e.mp.changedTouches[0] : {};  
      chart._zr.handler.dispatch('mouseup', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
      chart._zr.handler.dispatch('click', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
    }  
  }  
};  
</script>  

<style scoped>  
.ec-canvas {  
  width: 100%;  
  height: 100%;  
  flex: 1;  
}  
</style>  
继续阅读 »

这个错误是由于 prors不能传递方法(之前是可以的,不知道是平台的差异还是版本的差异);
解决办法 将echarts.js 直接导入到echarts.vue 中.

import * as echarts from '@/common/js/echarts.simple.min';

还有uni api 有变动 echarts.vue 中有两处需要修改

createCanvasContext() 第二个参数传入当前组建 即this,
createSelectorQuery() 后面加上调用 in(this).

echarts.vue 完整代码如下

<template>  
  <canvas v-if="canvasId" class="ec-canvas" :id="canvasId" :canvasId="canvasId" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd" @error="error"></canvas>  
</template>  

<script>  
import WxCanvas from './wx-canvas';  
import * as echarts from '@/common/js/echarts.simple.min';  

export default {  
  props: {  
    // echarts: {  
    //   required: true,  
    //   type: Object,  
    //   default() {  
    //     return echarts;  
    //   }  
    // },  
    onInit: {  
      required: true,  
      type: Function,  
      default: null  
    },  
    canvasId: {  
      type: String,  
      default: 'ec-canvas'  
    },  
    lazyLoad: {  
      type: Boolean,  
      default: false  
    },  
    disableTouch: {  
      type: Boolean,  
      default: false  
    },  
    throttleTouch: {  
      type: Boolean,  
      default: false  
    }  
  },  
  onReady() {  
    this.echarts = echarts;  

    if (!this.echarts) {  
      console.warn('组件需绑定 echarts 变量,例:<ec-canvas id="mychart-dom-bar" ' + 'canvas-id="mychart-bar" :echarts="echarts"></ec-canvas>');  
      return;  
    }  

    console.log('echarts');  
    console.log(this.onInit);  

    if (!this.lazyLoad) this.init();  
  },  
  methods: {  
    init() {  
      const version = wx.version.version.split('.').map(n => parseInt(n, 10));  
      const isValid = version[0] > 1 || (version[0] === 1 && version[1] > 9) || (version[0] === 1 && version[1] === 9 && version[2] >= 91);  
      if (!isValid) {  
        console.error('微信基础库版本过低,需大于等于 1.9.91。' + '参见:https://github.com/ecomfe/echarts-for-weixin' + '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');  
        return;  
      }  

      if (!this.onInit) {  
        console.warn('请传入 onInit 函数进行初始化');  
        return;  
      }  

      const canvasId = this.canvasId;  
      this.ctx = wx.createCanvasContext(canvasId,this);  

      const canvas = new WxCanvas(this.ctx, canvasId);  

      this.echarts.setCanvasCreator(() => canvas);  

      const query = wx.createSelectorQuery().in(this);  
      query  
        .select(`#${canvasId}`)  
        .boundingClientRect(res => {  
          if (!res) {  
            //setTimeout(() => this.init(), 200);  
            return;  
          }  

          this.chart = this.onInit(canvas, res.width, res.height);  
        })  
        .exec();  
    },  
    canvasToTempFilePath(opt) {  
      const { canvasId } = this;  
      this.ctx.draw(true, () => {  
        wx.canvasToTempFilePath({  
          canvasId,  
          ...opt  
        });  
      });  
    },  
    touchStart(e) {  
      const { disableTouch, chart } = this;  
      if (disableTouch || !chart || !e.mp.touches.length) return;  
      const touch = e.mp.touches[0];  
      chart._zr.handler.dispatch('mousedown', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
      chart._zr.handler.dispatch('mousemove', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
    },  
    touchMove(e) {  
      const { disableTouch, throttleTouch, chart, lastMoveTime } = this;  
      if (disableTouch || !chart || !e.mp.touches.length) return;  

      if (throttleTouch) {  
        const currMoveTime = Date.now();  
        if (currMoveTime - lastMoveTime < 240) return;  
        this.lastMoveTime = currMoveTime;  
      }  

      const touch = e.mp.touches[0];  
      chart._zr.handler.dispatch('mousemove', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
    },  
    touchEnd(e) {  
      const { disableTouch, chart } = this;  
      if (disableTouch || !chart) return;  
      const touch = e.mp.changedTouches ? e.mp.changedTouches[0] : {};  
      chart._zr.handler.dispatch('mouseup', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
      chart._zr.handler.dispatch('click', {  
        zrX: touch.x,  
        zrY: touch.y  
      });  
    }  
  }  
};  
</script>  

<style scoped>  
.ec-canvas {  
  width: 100%;  
  height: 100%;  
  flex: 1;  
}  
</style>  
收起阅读 »

iOS 苹果授权登录(Sign in with Apple)/Apple登录/苹果登录集成教程

Sign In with Apple 苹果授权登录 苹果登录 授权登录

此文档将不再维护,请参考新文档:https://uniapp.dcloud.io/tutorial/app-oauth-apple

HBuilderX 自 2.4.7+ 版本开始支持 Sign in with Apple (苹果登录),苹果登录是 iOS13 新增加的功能,当你的应用使用了第三方登录比如微信登录,同时也需要集成苹果登录,否则提交AppStore审核会被拒绝。

根据苹果审核指南要求,如果 app 使用第三方或社交登录服务 (例如,Facebook 登录、Google 登录、通过 Twitter 登录、通过 LinkedIn 登录、通过 Amazon 登录或微信登录) 来对其进行设置或验证这个 app 的用户主帐户,则该 app 必须同时提供“通过 Apple 登录”作为同等选项。详情参考:App Store 审核指南 - 通过 Apple 登录

使用苹果登录的教程

使用苹果登录首先需要在苹果开发者后台开启 App 的 Sign In with Apple 服务

注:只有发布Appstore的应用才能使用苹果登录。企业版开发者账号不支持 Sign In with Apple (企业版开发者账号指的是用于企业内部分发App,不能用于发布 App Store 的账号,也就是价格为 299$ 的账号)

1.登录到苹果开发者后台 编辑对应的 Identifier 勾选 Sign In with Apple 服务并保存

2.勾选或取消服务,会导致之前的 profile 描述文件失效,不需要新建,只要点击 Edit 重新编辑对应的 profile文件,然后保存下载使用新的profile文件即可

在 HBuilderX 编辑项目的 manifest.json ,在 App SDK配置中找到苹果登录,并勾选。

测试苹果登录服务,需要提交云打包或提交自定义基座打包,只有添加了苹果登录服务提交打包才会将苹果登录模块打进安装包,否则调不到相关方法

登录按钮样式

苹果对登录按钮样式有要求,请按照苹果要求统一设置登录按钮的样式,否则审核可能会被拒绝

需要注意的是:

  • 按钮必须在显著的位置(避免滑动屏幕才能看到)
  • 登录按钮有三种外观:白色,带有黑色轮廓线的白色和黑色,其他设计可能会影响审核;
  • 按钮圆角范围及按钮最小尺寸也有要求;
  • 具体规则请参考苹果 官方文档

下面是原生端默认的几种按钮样式供大家参考(width:130pt, height:30pt, corner radius: 6pt)


示例代码 (详细 api 请查阅 plus.oauth 文档)

注:因为是 iOS13+ 系统才支持苹果登录,所以建议在App的界面入口判断下,只有 iOS13 才显示Apple登录的选项

uni-app示例

uni.login({  
    provider: 'apple',  
    success: function (loginRes) {  
        // 登录成功  
        uni.getUserInfo({  
            provider: 'apple',  
            success() {  
                // 获取用户信息成功  
            }  
        })  
    },  
    fail: function (err) {  
        // 登录失败  
    }  
});  

5+App示例 (可以在 uniapp 中直接调用5+API)

注:因为是 iOS13+ 系统才支持苹果登录,所以在 iOS13 以下设备调用 plus.oauth.getServices 不会返回苹果登录对应的 service 对象

var appleOauth = null;  
plus.oauth.getServices(function(services) {  
    for (var i in services) {  
        var service = services[i];  
        // 获取苹果授权登录对象,苹果授权登录id 为 'apple' iOS13以下系统,不会返回苹果登录对应的 service    
        if (service.id == 'apple') {  
            appleOauth = service;  
            break;  
        }  
    }  
    appleOauth.login( function(oauth){  
        // 授权成功,苹果授权返回的信息在 oauth.target.appleInfo 中    
    }, function(err) {  
        // 授权失败 error  
    }, {  
        // 默认只会请求用户名字信息,如需请求用户邮箱信息,需要设置 scope: 'email'    
        scope: 'email'  
    })  
}, function(err) {  
    // 获取 services 失败  
})
5+ api 返回参数说明

注意:这里是 5+ api 返回的数据,uni 接口对 5+api 做了封装,以实际返回结果为准

appleInfo

属性 类型 说明
user String 苹果用户唯一标识符
state String 验证信息状态
email String 用户共享的可选电子邮件
fullName Object 用户共享的可选全名
authorizationCode String 验证数据
identityToken String Web令牌(JWT)
realUserStatus Number 标识用户是否为真实的人 0:当前平台不支持,忽略该值;1:无法确认;2:用户真实性非常高
scope String 返回信息作用域

fullName

属性 类型 说明
namePrefix String 名字前缀,头衔、敬称
givenName String 名字
middleName String 中间名
familyName String
nameSuffix String 名字后缀,学位、荣誉
nickName String 昵称

授权失败 code 说明

code 说明
1000 未知错误
1001 取消授权
1002 返回值无效
1003 请求未处理
1004 授权失败

注意事项

  1. 内置基座为企业证书签名不支持Sign in with Apple,需要提交云打包或制作自定义基座进行功能测试;
  2. 只有首次弹出登录授权框时才会有用户名及email的项(email需要配置 scope: 'email' ),并且用户可以删除或编辑用户名或隐藏用户邮箱,如果用户删除了用户名授权成功后fullname字段也会为空;
  3. 授权成功后再次调用登录接口会先校验上次授权是否依然有效,如有效,直接回调成功并返回上次授权成功时的数据,注意,此校验不会校验identityToken是否过期,需要用户自行处理;如果想每次都弹出授权框获取新的identityToken等信息,需要先调用'logout()',然后在调用登录接口就会弹出授权框,注意这时授权框内不会在出现用户名及邮箱,登录成功后这两个字段会为空,需要拿到 authorizationCode,identityToken 后传给服务器,然后和苹果服务器验证可获取用户名称等信息,具体请自行查阅文档;如果想在授权框中再次出现用户名或邮箱。需要在 系统设置->AppleID->密码与安全性->使用Apple ID 的 App 里面取消授权,然后再调用登录接口;
继续阅读 »

此文档将不再维护,请参考新文档:https://uniapp.dcloud.io/tutorial/app-oauth-apple

HBuilderX 自 2.4.7+ 版本开始支持 Sign in with Apple (苹果登录),苹果登录是 iOS13 新增加的功能,当你的应用使用了第三方登录比如微信登录,同时也需要集成苹果登录,否则提交AppStore审核会被拒绝。

根据苹果审核指南要求,如果 app 使用第三方或社交登录服务 (例如,Facebook 登录、Google 登录、通过 Twitter 登录、通过 LinkedIn 登录、通过 Amazon 登录或微信登录) 来对其进行设置或验证这个 app 的用户主帐户,则该 app 必须同时提供“通过 Apple 登录”作为同等选项。详情参考:App Store 审核指南 - 通过 Apple 登录

使用苹果登录的教程

使用苹果登录首先需要在苹果开发者后台开启 App 的 Sign In with Apple 服务

注:只有发布Appstore的应用才能使用苹果登录。企业版开发者账号不支持 Sign In with Apple (企业版开发者账号指的是用于企业内部分发App,不能用于发布 App Store 的账号,也就是价格为 299$ 的账号)

1.登录到苹果开发者后台 编辑对应的 Identifier 勾选 Sign In with Apple 服务并保存

2.勾选或取消服务,会导致之前的 profile 描述文件失效,不需要新建,只要点击 Edit 重新编辑对应的 profile文件,然后保存下载使用新的profile文件即可

在 HBuilderX 编辑项目的 manifest.json ,在 App SDK配置中找到苹果登录,并勾选。

测试苹果登录服务,需要提交云打包或提交自定义基座打包,只有添加了苹果登录服务提交打包才会将苹果登录模块打进安装包,否则调不到相关方法

登录按钮样式

苹果对登录按钮样式有要求,请按照苹果要求统一设置登录按钮的样式,否则审核可能会被拒绝

需要注意的是:

  • 按钮必须在显著的位置(避免滑动屏幕才能看到)
  • 登录按钮有三种外观:白色,带有黑色轮廓线的白色和黑色,其他设计可能会影响审核;
  • 按钮圆角范围及按钮最小尺寸也有要求;
  • 具体规则请参考苹果 官方文档

下面是原生端默认的几种按钮样式供大家参考(width:130pt, height:30pt, corner radius: 6pt)


示例代码 (详细 api 请查阅 plus.oauth 文档)

注:因为是 iOS13+ 系统才支持苹果登录,所以建议在App的界面入口判断下,只有 iOS13 才显示Apple登录的选项

uni-app示例

uni.login({  
    provider: 'apple',  
    success: function (loginRes) {  
        // 登录成功  
        uni.getUserInfo({  
            provider: 'apple',  
            success() {  
                // 获取用户信息成功  
            }  
        })  
    },  
    fail: function (err) {  
        // 登录失败  
    }  
});  

5+App示例 (可以在 uniapp 中直接调用5+API)

注:因为是 iOS13+ 系统才支持苹果登录,所以在 iOS13 以下设备调用 plus.oauth.getServices 不会返回苹果登录对应的 service 对象

var appleOauth = null;  
plus.oauth.getServices(function(services) {  
    for (var i in services) {  
        var service = services[i];  
        // 获取苹果授权登录对象,苹果授权登录id 为 'apple' iOS13以下系统,不会返回苹果登录对应的 service    
        if (service.id == 'apple') {  
            appleOauth = service;  
            break;  
        }  
    }  
    appleOauth.login( function(oauth){  
        // 授权成功,苹果授权返回的信息在 oauth.target.appleInfo 中    
    }, function(err) {  
        // 授权失败 error  
    }, {  
        // 默认只会请求用户名字信息,如需请求用户邮箱信息,需要设置 scope: 'email'    
        scope: 'email'  
    })  
}, function(err) {  
    // 获取 services 失败  
})
5+ api 返回参数说明

注意:这里是 5+ api 返回的数据,uni 接口对 5+api 做了封装,以实际返回结果为准

appleInfo

属性 类型 说明
user String 苹果用户唯一标识符
state String 验证信息状态
email String 用户共享的可选电子邮件
fullName Object 用户共享的可选全名
authorizationCode String 验证数据
identityToken String Web令牌(JWT)
realUserStatus Number 标识用户是否为真实的人 0:当前平台不支持,忽略该值;1:无法确认;2:用户真实性非常高
scope String 返回信息作用域

fullName

属性 类型 说明
namePrefix String 名字前缀,头衔、敬称
givenName String 名字
middleName String 中间名
familyName String
nameSuffix String 名字后缀,学位、荣誉
nickName String 昵称

授权失败 code 说明

code 说明
1000 未知错误
1001 取消授权
1002 返回值无效
1003 请求未处理
1004 授权失败

注意事项

  1. 内置基座为企业证书签名不支持Sign in with Apple,需要提交云打包或制作自定义基座进行功能测试;
  2. 只有首次弹出登录授权框时才会有用户名及email的项(email需要配置 scope: 'email' ),并且用户可以删除或编辑用户名或隐藏用户邮箱,如果用户删除了用户名授权成功后fullname字段也会为空;
  3. 授权成功后再次调用登录接口会先校验上次授权是否依然有效,如有效,直接回调成功并返回上次授权成功时的数据,注意,此校验不会校验identityToken是否过期,需要用户自行处理;如果想每次都弹出授权框获取新的identityToken等信息,需要先调用'logout()',然后在调用登录接口就会弹出授权框,注意这时授权框内不会在出现用户名及邮箱,登录成功后这两个字段会为空,需要拿到 authorizationCode,identityToken 后传给服务器,然后和苹果服务器验证可获取用户名称等信息,具体请自行查阅文档;如果想在授权框中再次出现用户名或邮箱。需要在 系统设置->AppleID->密码与安全性->使用Apple ID 的 App 里面取消授权,然后再调用登录接口;
收起阅读 »

分享几个适合做商城二次开发源码

云商城源码:https://www.aoym.cn/67511.html
小程序商店商城:https://www.aoym.cn/67426.html
服务商场兼职网:https://www.aoym.cn/10_5348.html
虚拟物品在线交易商城:https://www.aoym.cn/67314.html
小京东商城:https://www.aoym.cn/62362.html

继续阅读 »

云商城源码:https://www.aoym.cn/67511.html
小程序商店商城:https://www.aoym.cn/67426.html
服务商场兼职网:https://www.aoym.cn/10_5348.html
虚拟物品在线交易商城:https://www.aoym.cn/67314.html
小京东商城:https://www.aoym.cn/62362.html

收起阅读 »

其他地方获取当前页面的this,我测试的是安卓app

js

let that = getCurrentPages()[getCurrentPages().length -1].$vm;

let that = getCurrentPages()[getCurrentPages().length -1].$vm;

图像裁剪,原生实现,更流畅

图片裁剪 修改图片 图片加工 头像裁剪 拍照 插件

因试用canvas实现裁剪感觉不够流畅,而且相机感觉无法订制,在做拍题等软件时用户体验不好,于是开发一款基于原生的自定义相机、图片裁剪插件插件,进过多个用户体验,提出宝贵建议,新版本支持文字自定义、支持旋转、支持缩放、图标自定义等功能,如果有其他更好的需求,也可以提供给作者,作者根据实际情况也会在业余时间对插件进行不断完善

欢迎免费下载体验
https://ext.dcloud.net.cn/plugin?id=838

5+需要离线打包,如有需要也可联系作者。

继续阅读 »

因试用canvas实现裁剪感觉不够流畅,而且相机感觉无法订制,在做拍题等软件时用户体验不好,于是开发一款基于原生的自定义相机、图片裁剪插件插件,进过多个用户体验,提出宝贵建议,新版本支持文字自定义、支持旋转、支持缩放、图标自定义等功能,如果有其他更好的需求,也可以提供给作者,作者根据实际情况也会在业余时间对插件进行不断完善

欢迎免费下载体验
https://ext.dcloud.net.cn/plugin?id=838

5+需要离线打包,如有需要也可联系作者。

收起阅读 »