HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

android 指纹识别插件 离线打包版

更新:HTML5+已经自带指纹识别。http://www.html5plus.org/doc/zh_cn/fingerprint.html。以下文档已过期。

安卓问识别插件,需要离线打包才能使用,下面贴上代码:
AndroidManifest.xml 文件

<!--指纹识别权限-->  
    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
package com.mall.trade.util;  

import android.annotation.TargetApi;  
import android.app.KeyguardManager;  
import android.os.Build;  
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;  
import android.support.v4.os.CancellationSignal;  

import com.mall.trade.activity.MainActivity;  

/**  
 * Created by Alen   on 2017/11/15 0015.  
 * 指纹识别模块  
 */  
public class FingerprintUtil {  
    public static CancellationSignal cancellationSignal;  
    public static final int DEVICENOTSUPPORTED = 1011;//设备不支持  
    public static final int DEVICENOTSAFEGUARD = 1012;//设备未处于安全保护中  
    public static final int DEVICENOTREGUIDFIN = 1013;//设备没有注册过指纹  
    public static final int SUCCESS = 1000;//支持指纹识别  
    public static final int FINGETSUCCESS = 1002;//指纹识别成功  
    public static final int ERROR = 1001;//指纹识别失败  

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)  
    public static  void callFingerPrint(final OnCallBackListenr listener){  
        FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(MainActivity.getInstanse());  
        ResultObj res = checkFingerPrint(managerCompat);//检查指纹识别  
        if(res.getCode()!=SUCCESS){  
            if (listener != null){  
                if(res.getCode()==DEVICENOTSUPPORTED){//判断设备是否支持  
                    listener.onSupportFailed(res);  
                }else if(res.getCode()==DEVICENOTSAFEGUARD){//判断设备是否处于安全保护中  
                    listener.onInsecurity(res);  
                }else if(res.getCode()==DEVICENOTSAFEGUARD){//设备没有注册过指纹  
                    listener.onEnrollFailed(res);  
                }  
            }  
            return;  
        }  
        if (listener != null)  
            listener.onAuthenticationStart(res); //开始指纹识别  

        cancellationSignal  = new CancellationSignal(); //必须重新实例化,否则cancel 过一次就不能再使用了  
        managerCompat.authenticate(null,0,cancellationSignal,new FingerprintManagerCompat.AuthenticationCallback(){  
            // 当出现错误的时候回调此函数,比如多次尝试都失败了的时候,errString是错误信息,比如华为的提示就是:尝试次数过多,请稍后再试。  
            @Override  
            public void onAuthenticationError(int errMsgId, CharSequence errString) {  
                if (listener != null)  
                    listener.onAuthenticationError(errMsgId ,errString );  
            }  

            // 当指纹验证失败的时候会回调此函数,失败之后允许多次尝试,失败次数过多会停止响应一段时间然后再停止sensor的工作  
            @Override  
            public void onAuthenticationFailed() {  
                if (listener != null)  
                    listener.onAuthenticationFailed(new ResultObj(ERROR,"验证失败"));  
            }  

            @Override  
            public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {  
                if (listener != null)  
                    listener.onAuthenticationHelp(helpMsgId,helpString);  
            }  

            // 当验证的指纹成功时会回调此函数,然后不再监听指纹sensor  
            @Override  
            public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {  
                if (listener != null)  
                    listener.onAuthenticationSucceeded(result);  
            }  
            ;  
        },null);  

    }  

    /**  
     * 取消指纹识别  
     */  
    public static void cancelFingerPrint(){  
        if(cancellationSignal!=null){  
            cancellationSignal.cancel();  
        }  
    }  

    /**  
     * 判断当前设备是否支持指纹识别  
     * @return  
     */  
    public static ResultObj checkFingerPrint(){  
        FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(MainActivity.getInstanse());  
        return FingerprintUtil.checkFingerPrint(managerCompat);  
    }  

    /**  
     * 判断当前设备是否支持指纹识别  
     * @param managerCompat  
     * @return  
     */  
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)  
    public static ResultObj checkFingerPrint(FingerprintManagerCompat managerCompat){  
        if (!managerCompat.isHardwareDetected()){ //判断设备是否支持  
            return new ResultObj(FingerprintUtil.DEVICENOTSUPPORTED,"当前设备不支持指纹");  
        }  
        KeyguardManager keyguardManager =(KeyguardManager)MainActivity.getInstanse().getSystemService(MainActivity.getInstanse().KEYGUARD_SERVICE);  
        if (!keyguardManager.isKeyguardSecure()) {//判断设备是否处于安全保护中  
            return new ResultObj(FingerprintUtil.DEVICENOTSAFEGUARD,"当前设备没有设置密码保护");  
        }  
        if (!managerCompat.hasEnrolledFingerprints()){ //判断设备是否已经注册过指纹  
            return new ResultObj(FingerprintUtil.DEVICENOTREGUIDFIN,"还没有设置指纹");  
        }  
        return new ResultObj(FingerprintUtil.SUCCESS,"支持指纹识别");  
    }  

    public interface  OnCallBackListenr{  
        void onSupportFailed(ResultObj error);  
        void onInsecurity(ResultObj error);  
        void onEnrollFailed(ResultObj error);  
        void onAuthenticationStart(ResultObj error);  
        void onAuthenticationError(int errMsgId, CharSequence errString);  
        void onAuthenticationFailed(ResultObj error);  
        void onAuthenticationHelp(int helpMsgId, CharSequence helpString);  
        void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result);  
    }  

    public static class ResultObj{  
        private int code;  
        private String msg;  
        public ResultObj(int code,String msg){  
            this.code = code;  
            this.msg = msg;  
        }  

        public ResultObj getResult(){  
            return  this;  
        }  
        public int getCode(){  
            return  code;  
        }  
        public String getMsg(){  
            return  msg;  
        }  
    }  

    public static  void cancel(){  
        if (cancellationSignal != null)  
            cancellationSignal.cancel();  
    }  

}  

下面是调用代码:

/**  
     * 检查系统是否支持指纹识别  
     * @param pWebview  
     * @param array  
     */  
    public void checkFingerPrint(IWebview pWebview, JSONArray array){  
        String callbackId  = array.optString(0);  
        FingerprintUtil.ResultObj res = FingerprintUtil.checkFingerPrint();  
        if(res.getCode()==FingerprintUtil.SUCCESS){  
            String msg = toJSON(res.getCode(), res.getMsg());  
            Log.d("haiji", "FingerPrint " + res.getCode() + "  " + res.getMsg());  
            JSUtil.execCallback(pWebview,callbackId,msg, JSUtil.OK, false);//成功回调  
        }else{  
            Log.d("haiji", "FingerPrint "+res.getMsg());  
            String error = toJSON(res.getCode(), res.getMsg());  
            JSUtil.execCallback(pWebview,callbackId,error, JSUtil.ERROR, false);//失败回调  
        }  
    }  

    /**  
     * 开始进行指纹识别  
     * @param pWebview  
     * @param array  
     */  
    public void callFingerPrint(final IWebview pWebview, JSONArray array){  
        final String callbackId  = array.optString(0);  
        //开始指纹识别  
        FingerprintUtil.callFingerPrint(new FingerprintUtil.OnCallBackListenr() {  
            @Override  
            public void onSupportFailed(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+code.getMsg());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
//                JsObjectCommonMethod.showToast("当前设备不支持指纹");  
            }  

            @Override  
            public void onInsecurity(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+code.getMsg());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
//                JsObjectCommonMethod.showToast("当前设备没有设置密码保护");  
            }  

            @Override  
            public void onEnrollFailed(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+code.getMsg());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
            }  

            @Override  
            public void onAuthenticationStart(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+code.getMsg());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.OK, true);//成功回调  
            }  

            @Override  
            public void onAuthenticationError(int errMsgId, CharSequence errString) {  
                String error = toJSON(errMsgId, errString.toString());  
                Log.d("haiji", "FingerPrint "+error.toString());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
            }  

            @Override  
            public void onAuthenticationFailed(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+error);  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
            }  

            @Override  
            public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {  
                String error = toJSON(helpMsgId, helpString.toString());  
                Log.d("haiji", "FingerPrint "+error);  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
            }  

            @Override  
            public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {  
                String error = toJSON(FingerprintUtil.FINGETSUCCESS, "指纹识别成功");  
                Log.d("haiji", "FingerPrint "+error);  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.OK, false);//成功回调  
            }  
        });  
    }  

    /**  
     * 取消指纹识别  
     * @param pWebview  
     * @param array  
     */  
    public void calcelFingerPrint(final IWebview pWebview, JSONArray array){  
        Log.d("haiji", "FingerPrint 取消指纹识别");  
        FingerprintUtil.cancelFingerPrint();  
    }

下面是js中的代码

/**  
             * 指纹识别检测  
             * @param param  
             */  
            checkFingerPrint:function(successCbk,errorCbk){  
                var success = typeof successCbk !== 'function'? null:function(args){  
                        successCbk(args);  
                    }  
                var fail = typeof errorCbk !== 'function'?null:function(code){  
                        errorCbk(code);  
                    }  
                callbackID = BRIGE.callbackId(success,fail);  
                BRIGE.exec(_CLASS_NAME, "checkFingerPrint", [callbackID,""]);  
            },  
            /**  
             * 开始进行指纹识别  
             * @param param  
             */  
            callFingerPrint:function(successCbk,errorCbk){  
                var success = typeof successCbk !== 'function'? null:function(args){  
                        successCbk(args);  
                    }  
                var fail = typeof errorCbk !== 'function'?null:function(code){  
                        errorCbk(code);  
                    }  
                callbackID = BRIGE.callbackId(success,fail);  
                BRIGE.exec(_CLASS_NAME, "callFingerPrint", [callbackID,""]);  
            },  
            /**  
             * 取消指纹识别  
             * @param param  
             */  
            calcelFingerPrint:function(){  
                BRIGE.exec(_CLASS_NAME, "calcelFingerPrint", []);  
            },
继续阅读 »

更新:HTML5+已经自带指纹识别。http://www.html5plus.org/doc/zh_cn/fingerprint.html。以下文档已过期。

安卓问识别插件,需要离线打包才能使用,下面贴上代码:
AndroidManifest.xml 文件

<!--指纹识别权限-->  
    <uses-permission android:name="android.permission.USE_FINGERPRINT"/>
package com.mall.trade.util;  

import android.annotation.TargetApi;  
import android.app.KeyguardManager;  
import android.os.Build;  
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;  
import android.support.v4.os.CancellationSignal;  

import com.mall.trade.activity.MainActivity;  

/**  
 * Created by Alen   on 2017/11/15 0015.  
 * 指纹识别模块  
 */  
public class FingerprintUtil {  
    public static CancellationSignal cancellationSignal;  
    public static final int DEVICENOTSUPPORTED = 1011;//设备不支持  
    public static final int DEVICENOTSAFEGUARD = 1012;//设备未处于安全保护中  
    public static final int DEVICENOTREGUIDFIN = 1013;//设备没有注册过指纹  
    public static final int SUCCESS = 1000;//支持指纹识别  
    public static final int FINGETSUCCESS = 1002;//指纹识别成功  
    public static final int ERROR = 1001;//指纹识别失败  

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)  
    public static  void callFingerPrint(final OnCallBackListenr listener){  
        FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(MainActivity.getInstanse());  
        ResultObj res = checkFingerPrint(managerCompat);//检查指纹识别  
        if(res.getCode()!=SUCCESS){  
            if (listener != null){  
                if(res.getCode()==DEVICENOTSUPPORTED){//判断设备是否支持  
                    listener.onSupportFailed(res);  
                }else if(res.getCode()==DEVICENOTSAFEGUARD){//判断设备是否处于安全保护中  
                    listener.onInsecurity(res);  
                }else if(res.getCode()==DEVICENOTSAFEGUARD){//设备没有注册过指纹  
                    listener.onEnrollFailed(res);  
                }  
            }  
            return;  
        }  
        if (listener != null)  
            listener.onAuthenticationStart(res); //开始指纹识别  

        cancellationSignal  = new CancellationSignal(); //必须重新实例化,否则cancel 过一次就不能再使用了  
        managerCompat.authenticate(null,0,cancellationSignal,new FingerprintManagerCompat.AuthenticationCallback(){  
            // 当出现错误的时候回调此函数,比如多次尝试都失败了的时候,errString是错误信息,比如华为的提示就是:尝试次数过多,请稍后再试。  
            @Override  
            public void onAuthenticationError(int errMsgId, CharSequence errString) {  
                if (listener != null)  
                    listener.onAuthenticationError(errMsgId ,errString );  
            }  

            // 当指纹验证失败的时候会回调此函数,失败之后允许多次尝试,失败次数过多会停止响应一段时间然后再停止sensor的工作  
            @Override  
            public void onAuthenticationFailed() {  
                if (listener != null)  
                    listener.onAuthenticationFailed(new ResultObj(ERROR,"验证失败"));  
            }  

            @Override  
            public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {  
                if (listener != null)  
                    listener.onAuthenticationHelp(helpMsgId,helpString);  
            }  

            // 当验证的指纹成功时会回调此函数,然后不再监听指纹sensor  
            @Override  
            public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {  
                if (listener != null)  
                    listener.onAuthenticationSucceeded(result);  
            }  
            ;  
        },null);  

    }  

    /**  
     * 取消指纹识别  
     */  
    public static void cancelFingerPrint(){  
        if(cancellationSignal!=null){  
            cancellationSignal.cancel();  
        }  
    }  

    /**  
     * 判断当前设备是否支持指纹识别  
     * @return  
     */  
    public static ResultObj checkFingerPrint(){  
        FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(MainActivity.getInstanse());  
        return FingerprintUtil.checkFingerPrint(managerCompat);  
    }  

    /**  
     * 判断当前设备是否支持指纹识别  
     * @param managerCompat  
     * @return  
     */  
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)  
    public static ResultObj checkFingerPrint(FingerprintManagerCompat managerCompat){  
        if (!managerCompat.isHardwareDetected()){ //判断设备是否支持  
            return new ResultObj(FingerprintUtil.DEVICENOTSUPPORTED,"当前设备不支持指纹");  
        }  
        KeyguardManager keyguardManager =(KeyguardManager)MainActivity.getInstanse().getSystemService(MainActivity.getInstanse().KEYGUARD_SERVICE);  
        if (!keyguardManager.isKeyguardSecure()) {//判断设备是否处于安全保护中  
            return new ResultObj(FingerprintUtil.DEVICENOTSAFEGUARD,"当前设备没有设置密码保护");  
        }  
        if (!managerCompat.hasEnrolledFingerprints()){ //判断设备是否已经注册过指纹  
            return new ResultObj(FingerprintUtil.DEVICENOTREGUIDFIN,"还没有设置指纹");  
        }  
        return new ResultObj(FingerprintUtil.SUCCESS,"支持指纹识别");  
    }  

    public interface  OnCallBackListenr{  
        void onSupportFailed(ResultObj error);  
        void onInsecurity(ResultObj error);  
        void onEnrollFailed(ResultObj error);  
        void onAuthenticationStart(ResultObj error);  
        void onAuthenticationError(int errMsgId, CharSequence errString);  
        void onAuthenticationFailed(ResultObj error);  
        void onAuthenticationHelp(int helpMsgId, CharSequence helpString);  
        void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result);  
    }  

    public static class ResultObj{  
        private int code;  
        private String msg;  
        public ResultObj(int code,String msg){  
            this.code = code;  
            this.msg = msg;  
        }  

        public ResultObj getResult(){  
            return  this;  
        }  
        public int getCode(){  
            return  code;  
        }  
        public String getMsg(){  
            return  msg;  
        }  
    }  

    public static  void cancel(){  
        if (cancellationSignal != null)  
            cancellationSignal.cancel();  
    }  

}  

下面是调用代码:

/**  
     * 检查系统是否支持指纹识别  
     * @param pWebview  
     * @param array  
     */  
    public void checkFingerPrint(IWebview pWebview, JSONArray array){  
        String callbackId  = array.optString(0);  
        FingerprintUtil.ResultObj res = FingerprintUtil.checkFingerPrint();  
        if(res.getCode()==FingerprintUtil.SUCCESS){  
            String msg = toJSON(res.getCode(), res.getMsg());  
            Log.d("haiji", "FingerPrint " + res.getCode() + "  " + res.getMsg());  
            JSUtil.execCallback(pWebview,callbackId,msg, JSUtil.OK, false);//成功回调  
        }else{  
            Log.d("haiji", "FingerPrint "+res.getMsg());  
            String error = toJSON(res.getCode(), res.getMsg());  
            JSUtil.execCallback(pWebview,callbackId,error, JSUtil.ERROR, false);//失败回调  
        }  
    }  

    /**  
     * 开始进行指纹识别  
     * @param pWebview  
     * @param array  
     */  
    public void callFingerPrint(final IWebview pWebview, JSONArray array){  
        final String callbackId  = array.optString(0);  
        //开始指纹识别  
        FingerprintUtil.callFingerPrint(new FingerprintUtil.OnCallBackListenr() {  
            @Override  
            public void onSupportFailed(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+code.getMsg());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
//                JsObjectCommonMethod.showToast("当前设备不支持指纹");  
            }  

            @Override  
            public void onInsecurity(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+code.getMsg());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
//                JsObjectCommonMethod.showToast("当前设备没有设置密码保护");  
            }  

            @Override  
            public void onEnrollFailed(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+code.getMsg());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
            }  

            @Override  
            public void onAuthenticationStart(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+code.getMsg());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.OK, true);//成功回调  
            }  

            @Override  
            public void onAuthenticationError(int errMsgId, CharSequence errString) {  
                String error = toJSON(errMsgId, errString.toString());  
                Log.d("haiji", "FingerPrint "+error.toString());  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
            }  

            @Override  
            public void onAuthenticationFailed(FingerprintUtil.ResultObj code) {  
                String error = toJSON(code.getCode(), code.getMsg());  
                Log.d("haiji", "FingerPrint "+error);  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
            }  

            @Override  
            public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {  
                String error = toJSON(helpMsgId, helpString.toString());  
                Log.d("haiji", "FingerPrint "+error);  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.ERROR, false);//失败回调  
            }  

            @Override  
            public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {  
                String error = toJSON(FingerprintUtil.FINGETSUCCESS, "指纹识别成功");  
                Log.d("haiji", "FingerPrint "+error);  
                JSUtil.execCallback(pWebview, callbackId, error, JSUtil.OK, false);//成功回调  
            }  
        });  
    }  

    /**  
     * 取消指纹识别  
     * @param pWebview  
     * @param array  
     */  
    public void calcelFingerPrint(final IWebview pWebview, JSONArray array){  
        Log.d("haiji", "FingerPrint 取消指纹识别");  
        FingerprintUtil.cancelFingerPrint();  
    }

下面是js中的代码

/**  
             * 指纹识别检测  
             * @param param  
             */  
            checkFingerPrint:function(successCbk,errorCbk){  
                var success = typeof successCbk !== 'function'? null:function(args){  
                        successCbk(args);  
                    }  
                var fail = typeof errorCbk !== 'function'?null:function(code){  
                        errorCbk(code);  
                    }  
                callbackID = BRIGE.callbackId(success,fail);  
                BRIGE.exec(_CLASS_NAME, "checkFingerPrint", [callbackID,""]);  
            },  
            /**  
             * 开始进行指纹识别  
             * @param param  
             */  
            callFingerPrint:function(successCbk,errorCbk){  
                var success = typeof successCbk !== 'function'? null:function(args){  
                        successCbk(args);  
                    }  
                var fail = typeof errorCbk !== 'function'?null:function(code){  
                        errorCbk(code);  
                    }  
                callbackID = BRIGE.callbackId(success,fail);  
                BRIGE.exec(_CLASS_NAME, "callFingerPrint", [callbackID,""]);  
            },  
            /**  
             * 取消指纹识别  
             * @param param  
             */  
            calcelFingerPrint:function(){  
                BRIGE.exec(_CLASS_NAME, "calcelFingerPrint", []);  
            },
收起阅读 »

【分享】【开源】canvas图像裁剪、压缩、旋转

图片裁剪 图片压缩 技术分享 canvas 图像处理 源码分享

前言

前段时间遇到了一个移动端对图像进行裁剪、压缩、旋转的需求。
考虑到已有各轮子的契合度都不高,于是自己重新造了一个轮子。

关于图像裁剪、压缩

在HTML5时代,canvas的功能已经非常强大了,可以进行像素级的操作。像图像裁剪、压缩就都是基于canvas来实现的。

关于其中原理,无非就是利用canvas自带的API,复杂一点的就是裁剪框以及旋转后的坐标计算,因此不再赘述。

本文中的图像裁剪、压缩都是基于canvas完成的。

图像裁剪

功能包括:

  • canvas绘制图片

  • 裁剪框选择裁剪大小

  • 旋转功能

  • 放大镜(方便旋转)

  • 裁剪功能

  • 缩放、压缩功能(通过参数控制)

示例

https://dailc.github.io/image-process/examples/clip.html

image

效果

image
image
image
image
[图片上传失败...(image-c687d7-1510800462845)]

使用

引入

dist/image-clip.css  
dist/image-clip.js

全局变量

ImageClip

调用方法

var cropImage = new ImageClip(options);  

cropImage.method()

API

resetClipRect

重置裁剪框,重新变为最大

cropImage.resetClipRect();

clip

裁剪图像,根据当前的裁剪框进行裁剪

cropImage.clip();

getClipImgData

获取已裁剪的图像

var base64 = cropImage.getClipImgData();

rotate

旋转图片

cropImage.clip(isClockWise);

destroy

销毁当前的裁剪对象

如果一个容器需要重新生成裁剪对象,一定要先销毁以前的

cropImage.destroy();

更多

关于详细参数说明与更多使用

请参考源码

图像缩放

上述的图片裁剪中其实已经附带缩放功能,但是鉴于那是基于整套裁剪流程的,不满足一些场景(譬如只要针对图片压缩的)。

因此,单独又将图像缩放提取成一个模块,以适用于此类场景。

功能包括:

  • 图像的缩放、压缩

  • 一些常用的缩放算法(双立方,双线性,近邻)

示例

https://dailc.github.io/image-process/examples/scale.html

https://dailc.github.io/image-process/examples/scale_compress.html

image

效果

示例较为粗糙

image

使用

引入

dist/image-scale.js

全局变量

ImageScale

调用方法

ImageScale.method()

API

scaleImageData

ImageData类型的数据进行缩放,将数据放入新的ImageData

ImageScale.scaleImageData(imageData, newImageData, {  
    // 0: nearestNeighbor  
    // 1: bilinearInterpolation  
    // 2: bicubicInterpolation  
    // 3: bicubicInterpolation2  
    processType: 0,  
});

scaleImage

Image类型的对象进行缩放,返回一个base64字符串

var base64 = ImageScale.scaleImage(image, {  
    width: 80,  
    height: 80,  
    mime: 'image/png',  
    // 0: nearestNeighbor  
    // 1: bilinearInterpolation  
    // 2: bicubicInterpolation  
    // 3: bicubicInterpolation2  
    processType: 0,  
});

compressImage

compressImage,返回一个base64字符串

与scale的区别是这用的是canvas自动缩放,并且有很多参数可控

var base64 = ImageScale.compressImage(image, {  
    // 压缩质量  
    quality: 0.92,  
    mime: 'image/jpeg',  
    // 压缩时的放大系数,默认为1,如果增大,代表图像的尺寸会变大(最大不会超过原图)  
    compressScaleRatio: 1,  
    // ios的iPhone下主动放大一定系数以解决分辨率过小的模糊问题  
    iphoneFixedRatio: 2,  
    // 是否采用原图像素(不会改变大小)  
    isUseOriginSize: false,  
    // 增加最大宽度,增加后最大不会超过这个宽度  
    maxWidth: 0,  
    // 使用强制的宽度,如果使用,其它宽高比系数都会失效,默认整图使用这个宽度  
    forceWidth: 0,  
    // 同上,但是一般不建议设置,因为很可能会改变宽高比导致拉升,特殊场景下使用  
    forceHeight: 0,  
});

更多

关于详细参数说明与更多使用

请参考源码

完善与不足

虽然说一些注意的功能都已经实现,但是从细节角度考虑,还是有很多有待完善的地方的。

譬如,裁剪框的实现方式不优雅。

譬如,旋转不支持其它角度。

譬如,内部源码有待优化。

...

虽然说有计划未来某段时间重构,但考虑到实际的时间安排,可能得等到很后了。

源码

图像裁剪:

https://github.com/dailc/image-process/blob/master/src/clip/README.md

图像缩放:

https://github.com/dailc/image-process/blob/master/src/scale/README.md

继续阅读 »

前言

前段时间遇到了一个移动端对图像进行裁剪、压缩、旋转的需求。
考虑到已有各轮子的契合度都不高,于是自己重新造了一个轮子。

关于图像裁剪、压缩

在HTML5时代,canvas的功能已经非常强大了,可以进行像素级的操作。像图像裁剪、压缩就都是基于canvas来实现的。

关于其中原理,无非就是利用canvas自带的API,复杂一点的就是裁剪框以及旋转后的坐标计算,因此不再赘述。

本文中的图像裁剪、压缩都是基于canvas完成的。

图像裁剪

功能包括:

  • canvas绘制图片

  • 裁剪框选择裁剪大小

  • 旋转功能

  • 放大镜(方便旋转)

  • 裁剪功能

  • 缩放、压缩功能(通过参数控制)

示例

https://dailc.github.io/image-process/examples/clip.html

image

效果

image
image
image
image
[图片上传失败...(image-c687d7-1510800462845)]

使用

引入

dist/image-clip.css  
dist/image-clip.js

全局变量

ImageClip

调用方法

var cropImage = new ImageClip(options);  

cropImage.method()

API

resetClipRect

重置裁剪框,重新变为最大

cropImage.resetClipRect();

clip

裁剪图像,根据当前的裁剪框进行裁剪

cropImage.clip();

getClipImgData

获取已裁剪的图像

var base64 = cropImage.getClipImgData();

rotate

旋转图片

cropImage.clip(isClockWise);

destroy

销毁当前的裁剪对象

如果一个容器需要重新生成裁剪对象,一定要先销毁以前的

cropImage.destroy();

更多

关于详细参数说明与更多使用

请参考源码

图像缩放

上述的图片裁剪中其实已经附带缩放功能,但是鉴于那是基于整套裁剪流程的,不满足一些场景(譬如只要针对图片压缩的)。

因此,单独又将图像缩放提取成一个模块,以适用于此类场景。

功能包括:

  • 图像的缩放、压缩

  • 一些常用的缩放算法(双立方,双线性,近邻)

示例

https://dailc.github.io/image-process/examples/scale.html

https://dailc.github.io/image-process/examples/scale_compress.html

image

效果

示例较为粗糙

image

使用

引入

dist/image-scale.js

全局变量

ImageScale

调用方法

ImageScale.method()

API

scaleImageData

ImageData类型的数据进行缩放,将数据放入新的ImageData

ImageScale.scaleImageData(imageData, newImageData, {  
    // 0: nearestNeighbor  
    // 1: bilinearInterpolation  
    // 2: bicubicInterpolation  
    // 3: bicubicInterpolation2  
    processType: 0,  
});

scaleImage

Image类型的对象进行缩放,返回一个base64字符串

var base64 = ImageScale.scaleImage(image, {  
    width: 80,  
    height: 80,  
    mime: 'image/png',  
    // 0: nearestNeighbor  
    // 1: bilinearInterpolation  
    // 2: bicubicInterpolation  
    // 3: bicubicInterpolation2  
    processType: 0,  
});

compressImage

compressImage,返回一个base64字符串

与scale的区别是这用的是canvas自动缩放,并且有很多参数可控

var base64 = ImageScale.compressImage(image, {  
    // 压缩质量  
    quality: 0.92,  
    mime: 'image/jpeg',  
    // 压缩时的放大系数,默认为1,如果增大,代表图像的尺寸会变大(最大不会超过原图)  
    compressScaleRatio: 1,  
    // ios的iPhone下主动放大一定系数以解决分辨率过小的模糊问题  
    iphoneFixedRatio: 2,  
    // 是否采用原图像素(不会改变大小)  
    isUseOriginSize: false,  
    // 增加最大宽度,增加后最大不会超过这个宽度  
    maxWidth: 0,  
    // 使用强制的宽度,如果使用,其它宽高比系数都会失效,默认整图使用这个宽度  
    forceWidth: 0,  
    // 同上,但是一般不建议设置,因为很可能会改变宽高比导致拉升,特殊场景下使用  
    forceHeight: 0,  
});

更多

关于详细参数说明与更多使用

请参考源码

完善与不足

虽然说一些注意的功能都已经实现,但是从细节角度考虑,还是有很多有待完善的地方的。

譬如,裁剪框的实现方式不优雅。

譬如,旋转不支持其它角度。

譬如,内部源码有待优化。

...

虽然说有计划未来某段时间重构,但考虑到实际的时间安排,可能得等到很后了。

源码

图像裁剪:

https://github.com/dailc/image-process/blob/master/src/clip/README.md

图像缩放:

https://github.com/dailc/image-process/blob/master/src/scale/README.md

收起阅读 »

那些年绕不过的苹果上架审核

iOS

这个分类。。。。不太恰当
在分享我和苹果审核纠葛史前,还是有必要铺垫一下的。
我,大城市里平民阶层,工作时间是再不能更标准的朝九晚五,公司距离租的房子乘以6倍差不多才一站地铁的路,不刻意改变一下出门时间,甚至每天早上在路上看到的脸都是那几张。日复一日的两点一线,反倒是把心挠的痒痒。众所周知,豆瓣里人才济济,幽默风趣,针砭时事,侃侃而谈之士大有所在,头脑不太简单但生活太过简单的我极其轻易地被几篇打着“专治无聊”帖子吸引了去。最终,用一句话描述——我个人做起了APP。
非技术出身,没经验,海阔天空畅想后还是老实巴交照着豆瓣经验贴讲的去做了。挑了某某免费在线制作APP平台,研究了大半个月,搞清了平台APP制作逻辑,用了大半年去搭建界面,填充数据。因为APP没有涉及电商、医疗等特殊行业类别,所以没有选择代上架服务,而是自己花点钱申请了苹果个人开发者账号走了自助上架流程。
那么,激动人心又饱含心酸的旅程就此开始。
APP制作完备,资料准备充分,先是过了平台的自助上架审核然后自行上架到App Store。
由于关闭了启动图,我的第一次申请,就这么被App Store拒绝了。百度一下相似情况还真不少——为了增强应用程序启动时的用户体验,您应该提供一个启动图像。启动图像并不是为您提供机会进行艺术展示;它完全是为了增强用户对应用程序能够快速启动并立即投入使用的感知度,巴拉巴拉的。在制作台开启启动页后,重新打包,满腔自信再次提交上架申请。由于是社区类型App,版块还挺多,其中一个版块我加了不少链接,我的上架申请如愿以偿又被驳回了。苹果告诉我有链接堆砌的嫌疑,这种界面不适宜放在APP里,居然中肯建议我使用H5制作。足足用了两天改好了问题板块,对自己APP的内容审视再三,希望的火苗又一次点燃。
两天过后,我拿起了好几个月前放在枕头下的《金刚经》。我以为拥护苹果是一种美德,实则不然,APP中某一tab栏的图标风格带有浓郁ios icon风情,又一次,被拒绝了。第四次,也是最后一次。事实证明苹果审核人员真的十分认真负责,最后一次被拒绝也确实是我制作过程中疏忽了一个页面的顶栏返回按钮,点击过后的背景色被设置成了和白色页面背景形成强烈明暗对比的黑色,用户体验不友好,这个我完全认同。被苹果的火眼金睛发现了这一漏洞,调整好心态,改正,重新打包,提交,漫长而又让人心焦的等待......
最终,我的APP通过了苹果的审核。绿色的圆点+可供销售四个大字,对于每一位苹果开发者来说,视觉快感约等于通关游戏后的醒目弹窗。
一刹那,我很爽。
四次交手,内心吐槽苹果多次,更多却是欣赏它的严谨和求实,对每一位苹果开发者负责,更是对每一位ios用户负责。这一过程即便繁琐,也确实丰富了一名普通群众的业余生活,接触了曾经未曾涉及的领域。上架App Store是第一步,如何运营好自己的App是下一阶段该着重思考的问题了。
以上这些文字,能提炼出被App Store打回的原因有:启动页黑屏、APP制作不完善、链接堆砌、涉及苹果专有图标或文字。也可以总结出一条通用的“通过苹果ios上架审核的诀窍”——耐心。将心比心,你是iOS用户希望在App Store下载到什么样的应用,那就请以什么样的标准去制作和改进自己的App。制作App过程中遇到问题求助所用平台的专员或求助万能的搜索引擎,上架过程遇到阻碍,首选求助搜索引擎,其次是找不到根据的一些可以试着和苹果联系,他们的审核人员一般都会给出非常周到和中肯的建议。

最后附上: 2017 年最新Appstore审核条款

继续阅读 »

这个分类。。。。不太恰当
在分享我和苹果审核纠葛史前,还是有必要铺垫一下的。
我,大城市里平民阶层,工作时间是再不能更标准的朝九晚五,公司距离租的房子乘以6倍差不多才一站地铁的路,不刻意改变一下出门时间,甚至每天早上在路上看到的脸都是那几张。日复一日的两点一线,反倒是把心挠的痒痒。众所周知,豆瓣里人才济济,幽默风趣,针砭时事,侃侃而谈之士大有所在,头脑不太简单但生活太过简单的我极其轻易地被几篇打着“专治无聊”帖子吸引了去。最终,用一句话描述——我个人做起了APP。
非技术出身,没经验,海阔天空畅想后还是老实巴交照着豆瓣经验贴讲的去做了。挑了某某免费在线制作APP平台,研究了大半个月,搞清了平台APP制作逻辑,用了大半年去搭建界面,填充数据。因为APP没有涉及电商、医疗等特殊行业类别,所以没有选择代上架服务,而是自己花点钱申请了苹果个人开发者账号走了自助上架流程。
那么,激动人心又饱含心酸的旅程就此开始。
APP制作完备,资料准备充分,先是过了平台的自助上架审核然后自行上架到App Store。
由于关闭了启动图,我的第一次申请,就这么被App Store拒绝了。百度一下相似情况还真不少——为了增强应用程序启动时的用户体验,您应该提供一个启动图像。启动图像并不是为您提供机会进行艺术展示;它完全是为了增强用户对应用程序能够快速启动并立即投入使用的感知度,巴拉巴拉的。在制作台开启启动页后,重新打包,满腔自信再次提交上架申请。由于是社区类型App,版块还挺多,其中一个版块我加了不少链接,我的上架申请如愿以偿又被驳回了。苹果告诉我有链接堆砌的嫌疑,这种界面不适宜放在APP里,居然中肯建议我使用H5制作。足足用了两天改好了问题板块,对自己APP的内容审视再三,希望的火苗又一次点燃。
两天过后,我拿起了好几个月前放在枕头下的《金刚经》。我以为拥护苹果是一种美德,实则不然,APP中某一tab栏的图标风格带有浓郁ios icon风情,又一次,被拒绝了。第四次,也是最后一次。事实证明苹果审核人员真的十分认真负责,最后一次被拒绝也确实是我制作过程中疏忽了一个页面的顶栏返回按钮,点击过后的背景色被设置成了和白色页面背景形成强烈明暗对比的黑色,用户体验不友好,这个我完全认同。被苹果的火眼金睛发现了这一漏洞,调整好心态,改正,重新打包,提交,漫长而又让人心焦的等待......
最终,我的APP通过了苹果的审核。绿色的圆点+可供销售四个大字,对于每一位苹果开发者来说,视觉快感约等于通关游戏后的醒目弹窗。
一刹那,我很爽。
四次交手,内心吐槽苹果多次,更多却是欣赏它的严谨和求实,对每一位苹果开发者负责,更是对每一位ios用户负责。这一过程即便繁琐,也确实丰富了一名普通群众的业余生活,接触了曾经未曾涉及的领域。上架App Store是第一步,如何运营好自己的App是下一阶段该着重思考的问题了。
以上这些文字,能提炼出被App Store打回的原因有:启动页黑屏、APP制作不完善、链接堆砌、涉及苹果专有图标或文字。也可以总结出一条通用的“通过苹果ios上架审核的诀窍”——耐心。将心比心,你是iOS用户希望在App Store下载到什么样的应用,那就请以什么样的标准去制作和改进自己的App。制作App过程中遇到问题求助所用平台的专员或求助万能的搜索引擎,上架过程遇到阻碍,首选求助搜索引擎,其次是找不到根据的一些可以试着和苹果联系,他们的审核人员一般都会给出非常周到和中肯的建议。

最后附上: 2017 年最新Appstore审核条款

收起阅读 »

用ui.openWindow添加链接跳转,只能跳一次,再跳就显示上一个页面

用ui.openWindow添加链接跳转,只能跳一次,再跳就显示上一个页面,并且没有了跳转的动画效果。
解决办法:只要添加createNew:true,即可,即新建页面。每次跳转都新建页面,就完美解决了跳转白屏的问题。
注意,此处没有用a链接,用的是mui.openWindow。

继续阅读 »

用ui.openWindow添加链接跳转,只能跳一次,再跳就显示上一个页面,并且没有了跳转的动画效果。
解决办法:只要添加createNew:true,即可,即新建页面。每次跳转都新建页面,就完美解决了跳转白屏的问题。
注意,此处没有用a链接,用的是mui.openWindow。

收起阅读 »

Android平台以WebView方式集成HTML5+SDK 播放视频全屏时白屏

Android平台以WebView方式集成HTML5+SDK 播放视频全屏时白屏,视频播放有声音.
这个问题困扰了好久.后面跟踪代码发现在WebJsEvent.java文件中655行有问题,取不到IActivityHandler对象,导致代码不往下执行了

解决办法:在activity中实现IActivityHandler接口,并且在obtainActivityContentView方法中返回你当前的布局对象就可以了!
PS:官方的文档没说要实现这个接口

@Override  
    public FrameLayout obtainActivityContentView() {  
        return obtainActivityContentView;  
    }
继续阅读 »

Android平台以WebView方式集成HTML5+SDK 播放视频全屏时白屏,视频播放有声音.
这个问题困扰了好久.后面跟踪代码发现在WebJsEvent.java文件中655行有问题,取不到IActivityHandler对象,导致代码不往下执行了

解决办法:在activity中实现IActivityHandler接口,并且在obtainActivityContentView方法中返回你当前的布局对象就可以了!
PS:官方的文档没说要实现这个接口

@Override  
    public FrameLayout obtainActivityContentView() {  
        return obtainActivityContentView;  
    }
收起阅读 »

升级检测 - wap2app教程

升级 wap2app

wap2app项目的发行方式及对应的升级模式:

  • 发行成原生安装包,类似5+ App安装包,需开发者自己处理升级更新;
  • 发行到流应用平台,,流应用有内置的升级逻辑,开发者只需要将最新版本提交到流应用平台即可,无需单独开发.

本文主要讲解发行成原生安装包的升级检测实现,给出一种实现示例(仅供参考,开发者可以自定义逻辑实现),主要分为两个部分:

  • 客户端:App启动时,向服务器上报当前版本号,根据服务器响应结果决定是否提醒用户升级
  • 服务端:保存App最新版本号,根据客户端上报的版本号,比对后决定是否需要升级,若需升级则返回升级信息(rease notes、更新包地址等);

接口约定

如下数据接口约定仅为示例,开发者可以自定义接口参数。

请求地址:http://www.example.com/check/update

请求方法:GET

请求数据:

{  
    "appid": plus.runtime.appid,  
    "version": plus.runtime.version  
}

响应数据:

{  
    "status":1,//升级标志,1:需要升级;0:无需升级  
    "title": "wap2app版本更新",  
    "note": "修复bug1;\n修复bug2;",//release notes  
    "url": "http://www.example.com/wap2app.apk" //更新包下载地址  
}  

Tips:若应用已经是最新版本,无需升级,则服务端仅需返回status字段(并将值设为0),其它字段无需返回;

客户端实现

在app.js的onLaunch事件中,发起升级检测请求,如下:

/**  
* 当wap2app初始化完成时,会触发 onLaunch(全局只触发一次)  
* @param {Object} options  
*/  
onLaunch: function(options) {  
    //TODO wap2app其它初始化代码  

    /************升级检测代码开始********** */  
    var ua = navigator.userAgent;  
    //Html5Plus环境,但不是流应用环境  
    if(ua.indexOf('Html5Plus')>-1 && ua.indexOf('StreamApp')==-1){  
        var url = "http://www.example.com/check/update";//检查更新地址  
        var req = {//升级检测数据  
            "appid": plus.runtime.appid,  
            "version": plus.runtime.version  
        };  

        wap2app.ajax.get(url, req, function(rsp) {  
            if(rsp && rsp.status){  
                //需要更新,提示用户  
                plus.nativeUI.confirm(rsp.note, function(event) {  
                    if(0 == event.index) {//用户点击了“立即更新”按钮  
                        plus.runtime.openURL(rsp.url);  
                    }  
                }, rsp.title, ["立即更新", "取  消"]);  
            }              
        });  
    }  
    /************升级检测代码结束********** */  
}

服务端实现

推荐使用通过uniCloud的云函数模板,快速实现升级检查逻辑,详情参考:https://ext.dcloud.net.cn/plugin?id=2226

开发者也可以根据根据M站的开发语言,自己实现升级检测逻辑,如下是一个php示例代码:

$appid = $_GET['appid'];  
$version = $_GET['version'];//客户端版本号  
$rsp = array('status' => 0);//默认返回值,不需要升级  
if (isset($appid) && isset($version)) {  
    if($appid=="__W2A__m.example.com"){//校验appid  
        //这里是示例代码,真实业务上,最新版本号及relase notes可以存储在数据库或文件中  
        if($version !== "1.0.1"){  
            $rsp['status'] = 1;  
            $rsp['title'] = "应用更新";  
            $rsp['note'] = "修复bug1;\n修复bug2;";//release notes,支持换行  
            $rsp['url'] = "http://www.example.com/wap2app.apk";//应用升级包下载地址  
        }  
    }  
}   
exit(json_encode($rsp));
继续阅读 »

wap2app项目的发行方式及对应的升级模式:

  • 发行成原生安装包,类似5+ App安装包,需开发者自己处理升级更新;
  • 发行到流应用平台,,流应用有内置的升级逻辑,开发者只需要将最新版本提交到流应用平台即可,无需单独开发.

本文主要讲解发行成原生安装包的升级检测实现,给出一种实现示例(仅供参考,开发者可以自定义逻辑实现),主要分为两个部分:

  • 客户端:App启动时,向服务器上报当前版本号,根据服务器响应结果决定是否提醒用户升级
  • 服务端:保存App最新版本号,根据客户端上报的版本号,比对后决定是否需要升级,若需升级则返回升级信息(rease notes、更新包地址等);

接口约定

如下数据接口约定仅为示例,开发者可以自定义接口参数。

请求地址:http://www.example.com/check/update

请求方法:GET

请求数据:

{  
    "appid": plus.runtime.appid,  
    "version": plus.runtime.version  
}

响应数据:

{  
    "status":1,//升级标志,1:需要升级;0:无需升级  
    "title": "wap2app版本更新",  
    "note": "修复bug1;\n修复bug2;",//release notes  
    "url": "http://www.example.com/wap2app.apk" //更新包下载地址  
}  

Tips:若应用已经是最新版本,无需升级,则服务端仅需返回status字段(并将值设为0),其它字段无需返回;

客户端实现

在app.js的onLaunch事件中,发起升级检测请求,如下:

/**  
* 当wap2app初始化完成时,会触发 onLaunch(全局只触发一次)  
* @param {Object} options  
*/  
onLaunch: function(options) {  
    //TODO wap2app其它初始化代码  

    /************升级检测代码开始********** */  
    var ua = navigator.userAgent;  
    //Html5Plus环境,但不是流应用环境  
    if(ua.indexOf('Html5Plus')>-1 && ua.indexOf('StreamApp')==-1){  
        var url = "http://www.example.com/check/update";//检查更新地址  
        var req = {//升级检测数据  
            "appid": plus.runtime.appid,  
            "version": plus.runtime.version  
        };  

        wap2app.ajax.get(url, req, function(rsp) {  
            if(rsp && rsp.status){  
                //需要更新,提示用户  
                plus.nativeUI.confirm(rsp.note, function(event) {  
                    if(0 == event.index) {//用户点击了“立即更新”按钮  
                        plus.runtime.openURL(rsp.url);  
                    }  
                }, rsp.title, ["立即更新", "取  消"]);  
            }              
        });  
    }  
    /************升级检测代码结束********** */  
}

服务端实现

推荐使用通过uniCloud的云函数模板,快速实现升级检查逻辑,详情参考:https://ext.dcloud.net.cn/plugin?id=2226

开发者也可以根据根据M站的开发语言,自己实现升级检测逻辑,如下是一个php示例代码:

$appid = $_GET['appid'];  
$version = $_GET['version'];//客户端版本号  
$rsp = array('status' => 0);//默认返回值,不需要升级  
if (isset($appid) && isset($version)) {  
    if($appid=="__W2A__m.example.com"){//校验appid  
        //这里是示例代码,真实业务上,最新版本号及relase notes可以存储在数据库或文件中  
        if($version !== "1.0.1"){  
            $rsp['status'] = 1;  
            $rsp['title'] = "应用更新";  
            $rsp['note'] = "修复bug1;\n修复bug2;";//release notes,支持换行  
            $rsp['url'] = "http://www.example.com/wap2app.apk";//应用升级包下载地址  
        }  
    }  
}   
exit(json_encode($rsp));
收起阅读 »

mui 初学者开发视频

mui

mui 初学者开发视频 有需要的练习我 QQ 2748181236

mui 初学者开发视频 有需要的练习我 QQ 2748181236

新上一套MUI框架app界面模板

mui

新上一套MUI框架app界面模板,高性能MUI框架模板,分享给大家
http://www.sucaihuo.com/templates/3694.html

mui

继续阅读 »

新上一套MUI框架app界面模板,高性能MUI框架模板,分享给大家
http://www.sucaihuo.com/templates/3694.html

mui

收起阅读 »

British Type Hose Clamp Made in China

1.Our History
Weifang haihon International Co., Ltd has focused on top quality hose clamps for over 8 years in China. We started as a small operation, but now have become one of the leading suppliers in the fastener industry in China.
Today, Weifang haihon has been one of the top suppliers of quality hose clamps, such as: German type hose clamps, American type hose clamps. British type hose clamp and Heavy duty clamps.

2.Our Factory
We produce various of hose clamps and pipe coupling with different material. The annual production capacity reaches 100 million pieces or sets

3.Our Product
Weifang Haihon Products includes the following:
1, German type hose clamp
2, American type hose clamp
3, British type hose clamp
4, Heavy duty clamp
5, Mini Hose clamp
We supply our hose clamps to many countries, such as Germany, USA, Canada, Italy, Spain, Poland, Russia and so on. They are well received these years.

4.Product Application
Hose clamps are widely used for water, oil, steam and dust in automobile, gasoline engine, diesel engine, machine equipment, boat, mine, petroleum, chemical industry and agriculture. It is an ideal connection fastening.

5.Our Certificate
We always feel that all success of our company is directly related to the quality of the products we offer. We have got certificate of ISO9001, ISO/TS16949, SGS.

6.Production Equipment
We have modernized manufacture facilities, quality control systems and assemble lines.

7.Production Market
Our main export market:
Europe 45%
North America 20%
Asia 20%
South America 10%

8.Our service
We control the product quality critically for every step from material purchasing to production process.Our products are made by excellent steel material with advantages as skillful technique, strict test, strong fastening force and excellent endurance.
We trust your benefit is top important, so we will try to improve quality and control cost to meet your requirements.British Type Hose Clamp Made in China
website:http://www.haihonclamp.com/
website2:http://www.h-hoseclamp.com/

继续阅读 »

1.Our History
Weifang haihon International Co., Ltd has focused on top quality hose clamps for over 8 years in China. We started as a small operation, but now have become one of the leading suppliers in the fastener industry in China.
Today, Weifang haihon has been one of the top suppliers of quality hose clamps, such as: German type hose clamps, American type hose clamps. British type hose clamp and Heavy duty clamps.

2.Our Factory
We produce various of hose clamps and pipe coupling with different material. The annual production capacity reaches 100 million pieces or sets

3.Our Product
Weifang Haihon Products includes the following:
1, German type hose clamp
2, American type hose clamp
3, British type hose clamp
4, Heavy duty clamp
5, Mini Hose clamp
We supply our hose clamps to many countries, such as Germany, USA, Canada, Italy, Spain, Poland, Russia and so on. They are well received these years.

4.Product Application
Hose clamps are widely used for water, oil, steam and dust in automobile, gasoline engine, diesel engine, machine equipment, boat, mine, petroleum, chemical industry and agriculture. It is an ideal connection fastening.

5.Our Certificate
We always feel that all success of our company is directly related to the quality of the products we offer. We have got certificate of ISO9001, ISO/TS16949, SGS.

6.Production Equipment
We have modernized manufacture facilities, quality control systems and assemble lines.

7.Production Market
Our main export market:
Europe 45%
North America 20%
Asia 20%
South America 10%

8.Our service
We control the product quality critically for every step from material purchasing to production process.Our products are made by excellent steel material with advantages as skillful technique, strict test, strong fastening force and excellent endurance.
We trust your benefit is top important, so we will try to improve quality and control cost to meet your requirements.British Type Hose Clamp Made in China
website:http://www.haihonclamp.com/
website2:http://www.h-hoseclamp.com/

收起阅读 »

德艺网络科技-长期承接外包业务,欢迎各位中介、个人咨询!

外包 HTML5+ 移动APP PHP

德艺网络科技DES专案组多年活跃于服务产业,专注于企业品牌形象包装 ,网络营销 ,形象包装以及活动策划等各个领域.现拥有1000余家客户。
提供PC、wap、app建站,7年网络营销建站经验。

技能: 全新开发 手机网站 IOS开发 Android开发 微信开发

继续阅读 »

德艺网络科技DES专案组多年活跃于服务产业,专注于企业品牌形象包装 ,网络营销 ,形象包装以及活动策划等各个领域.现拥有1000余家客户。
提供PC、wap、app建站,7年网络营销建站经验。

技能: 全新开发 手机网站 IOS开发 Android开发 微信开发

收起阅读 »

接APP 前端工作

开发过一个完整的电商类项目了 关于供应方面的后台管理系统也开发过
有感兴趣的可以++280916522

开发过一个完整的电商类项目了 关于供应方面的后台管理系统也开发过
有感兴趣的可以++280916522

Barcod二维码扫描及其结果在webview中的信息的传递

mui

图1为二维码效果图,图二是扫码后返回结果并关闭扫码页面。
直接上代码
<!doctype html>
<html>

<head>  
    <meta charset="utf-8">  
    <meta http-equiv="Access-Control-Allow-Origin" content="*">  
    <meta http-equiv="content-security-policy">  
    <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no">  
    <meta name="apple-mobile-web-app-capable" content="yes">  
    <meta name="apple-mobile-web-app-status-bar-style" content="black">  
    <link href="../../WEB-INF/plug/mui/css/mui.min.css" rel="stylesheet" />  
    <script src="../../WEB-INF/plug/mui/js/mui.min.js"></script>  
    <script type="text/javascript" src="../../WEB-INF/plug/js/security.js"></script>  
    <script type="text/javascript" src="../../WEB-INF/plug/js/common.js"></script>  
    <style type="text/css">  
        #bcid {  
            width: 100%;  
            height: 100%;  
            position: absolute;  
            background: #000000;  
        }  

        html,  
        body,  
        div {  
            height: 100%;  
            width: 100%;  
        }  

        .fbt {  
            color: #ffffff;  
            width: 50%;  
            float: left;  
            line-height: 44px;  
            text-align: center;  
        }  
    </style>  
</head>  

<body>  
    <header class="mui-bar mui-bar-nav" style="background-color: rgba(221, 221, 221, 0);z-index: 99999;">  

        <h1 class="mui-title" style="color: #ffffff;">二维码扫描</h1>  
        <span class="mui-icon mui-icon-spinner-cycle mui-spin mui-pull-right" id="turnTheLight"></span>  
    </header>  

    <div id="bcid">  
        <!--盛放扫描控件的div-->  
    </div>  

    <div style="background-color: rgba(221, 221, 221, 0);z-index: 99999" class="mui-bar mui-bar-footer" style="padding: 0px;">  
        <div class="fbt" onclick="scanPicture();">从相册选择二维码</div>  
        <div class="fbt mui-action-back">取  消</div>  
    </div>  

    <script type="text/javascript">  
        var height = window.innerHeight + 'px'; //获取页面实际高度    
        var width = window.innerWidth + 'px';  
        document.getElementById("bcid").style.height = height;  
        document.getElementById("bcid").style.width = width;  

        scan = null; //扫描对象    
        mui.plusReady(function() { //通过mui初始化扫描  
            mui.init();  
            setTimeout("startRecognize()", 300)  

        });  

        function startRecognize() { //开启扫描  
            try {  
                var filter;  
                //自定义的扫描控件样式    
                var styles = {  
                    frameColor: "#29E52C",  
                    scanbarColor: "#29E52C",  
                    background: "rgba(255,255,255,-20)"  
                }  
                //扫描控件构造    
                scan = new plus.barcode.Barcode('bcid', filter, styles);  
                scan.onmarked = onmarked;  
                scan.onerror = onerror; //扫描错误  
                scan.start();  
                //打开关闭闪光灯处理    
                var flag = false;  
                document.getElementById("turnTheLight").addEventListener('tap', function() {  
                    if(flag == false) {  
                        scan.setFlash(true);  
                        flag = true;  
                    } else {  
                        scan.setFlash(false);  
                        flag = false;  
                    }  
                });  
            } catch(e) {  
                mui.toast("出现错误啦:\n" + e)  
            }  
        };  

        function onerror(e) { //错误弹框  
            alert(e);  
        };  

        function onmarked(type, result) { //这个是扫描二维码的回调函数,type是扫描二维码回调的类型  
            var text = '';  
            switch(type) { //QR,EAN13,EAN8都是二维码的一种编码格式,result是返回的结果  
                case plus.barcode.QR:  
                    text = 'QR: ';  
                    break;  
                case plus.barcode.EAN13:  
                    text = 'EAN13: ';  
                    break;  
                case plus.barcode.EAN8:  
                    text = 'EAN8: ';  
                    break;  
            }   
            smresult(result);  
        };  

        // 从相册中选择二维码图片     
        function scanPicture() { //可以直接识别二维码图片  
            plus.gallery.pick(function(path) {  
                plus.barcode.scan(path, onmarked, function(error) {  
                    //plus.nativeUI.alert("无法识别此图片");  
                    mui.toast("无法识别此图片");  
                });  
            }, function(err) {  
                plus.nativeUI.alert("Failed: " + err.message);  
            });  
        }  
        //关闭扫码页面  
        function closeSm() {  
            scan.close();  
            plus.webview.currentWebview().close('none');  
        }  
        //结果处理  
        function smresult(result) {  
            var bType = getBarcodeType(result);//二维吗类型  
            var type = localStorage.getItem("type");  
            if(type == "addfile") {  
                //添加档案扫码处理  

                if(bType==TMLX_JDCDA||bType==TMLX_JSZDA) {  
                    var tmnr = result;  
                    tmnr = getUrlp(tmnr);  
                    var params = "{" + "'method':'getTmxx'," + "'tmnr':" + "'" + tmnr + "'" + "}"  
                    var datajson = eval('(' + getData(params) + ')');  
                    var str = '<li><input class="file-num" value="' + datajson.obj.FILE_NUMBER + '" type="text"   /><i onclick="remove(this)">╳</i></li>'  
                    var wn = plus.webview.currentWebview(); //获取当前窗口的WebviewObject对象,即B   
                    var wvA = wn.opener(); //获取当前窗口的创建者,即A    
                    wvA.evalJS("addNew('" + str + "')"); //执行父窗口中的方法  A中的addNew方法    
                    plus.webview.currentWebview().close(); //扫码成功,关闭当前webview  
                } else {  
                    mui.toast("请扫描档案二维码")  
                    scan.start();  
                }  
            } else if(type == "getgezi") {  
                //扫码格子获取格子信息  
                if(bType==TMLX_JDCDA||bType==TMLX_JSZDA) {  
                gezism(result);  
                var wn = plus.webview.currentWebview(); //获取当前窗口的WebviewObject对象,即B   
                var wvA = wn.opener(); //获取当前窗口的创建者,即A    
                wvA.evalJS("addGeZi('" + str + "')"); //执行父窗口中的方法  A中的addNew方法    
                plus.webview.currentWebview().close(); //扫码成功,关闭当前webview  
                localStorage.setItem("ifFrist", "none"); //设置不是首次调用  
                }else{  
                    mui.toast("请扫描格子二维码")  
                    scan.start();  
                }  
            } else if(type == "sys") {  

                if(bType == TMLX_GEZI) {  
                    /**条码类型:格子*/  
                    var btnArray = ['取消', '确认'];  
                    mui.confirm("是否进行入库操作?", "提示", btnArray, function(e) {  
                        if(e.index == 1) {  

                            localStorage.setItem("ifFrist", "none"); //设置不是首次调用避免重复扫码  
                            localStorage.setItem("sysSign", "true");  
                            var str =gezism(result);  
                            localStorage.setItem("str", str);  
                            var webview = mui.openWindow({  
                                url: "../rk/rk.html",  
                                id: "rk.html",  
                                waiting: {  
                                    autoShow: false //自动显示等待框,默认为true  
                                },  
                                createNew: true  
                            });  
                            setTimeout("plus.webview.currentWebview().close()", 300)//扫码成功,关闭当前webview  

                        } else {  
                            scan.start();  
                        }  
                    });  
                } else if(bType == TMLX_JDCDA) {  
                    /**条码类型:机动车档案*/  
                    alert("条码类型:机动车档案");  
                    scan.start();  
                } else if(bType == TMLX_JSZDA) {  
                    /**条码类型:驾驶证档案*/  
                    alert("条码类型:驾驶证档案");  
                    scan.start();  
                } else if(bType == TMLX_DAG) {  
                    /**条码类型:档案柜*/  
                    alert("条码类型:档案柜");  
                    scan.start();  
                }  

            }  

        }  
        //格子扫码操作  
        function gezism(result) {  
            var tmnr = result;  
            tmnr = getUrlp(tmnr);  
            var params = "{" + "'method':'getTmxx'," + "'tmnr':" + "'" + tmnr + "'" + "}"  
            var datajson = eval('(' + getData(params) + ')');  
            //获取格子最大序号  
            var param2 = "{" + "'method':'getDaccxh'," + "'gzcode':" + "'" + datajson.obj.GZCODE + "'" + "}"  
            var dataxh = eval('(' + getData(param2) + ')');  
            var str = '<li><i>编码:' + datajson.obj.GZCODE + '</i><i>已存数:' + dataxh.obj.xh + '</i></li>';  
            str += '<li><i>行:' + datajson.obj.ROS + '</i><i>列:' + datajson.obj.COLS + '</i><i>面:' + datajson.obj.ASPECT + '</i></li>'  
            localStorage.setItem("gzcode", datajson.obj.GZCODE); //gz保存code  
            return str;  
        }  
    </script>  
</body>  

</html>

继续阅读 »

图1为二维码效果图,图二是扫码后返回结果并关闭扫码页面。
直接上代码
<!doctype html>
<html>

<head>  
    <meta charset="utf-8">  
    <meta http-equiv="Access-Control-Allow-Origin" content="*">  
    <meta http-equiv="content-security-policy">  
    <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no">  
    <meta name="apple-mobile-web-app-capable" content="yes">  
    <meta name="apple-mobile-web-app-status-bar-style" content="black">  
    <link href="../../WEB-INF/plug/mui/css/mui.min.css" rel="stylesheet" />  
    <script src="../../WEB-INF/plug/mui/js/mui.min.js"></script>  
    <script type="text/javascript" src="../../WEB-INF/plug/js/security.js"></script>  
    <script type="text/javascript" src="../../WEB-INF/plug/js/common.js"></script>  
    <style type="text/css">  
        #bcid {  
            width: 100%;  
            height: 100%;  
            position: absolute;  
            background: #000000;  
        }  

        html,  
        body,  
        div {  
            height: 100%;  
            width: 100%;  
        }  

        .fbt {  
            color: #ffffff;  
            width: 50%;  
            float: left;  
            line-height: 44px;  
            text-align: center;  
        }  
    </style>  
</head>  

<body>  
    <header class="mui-bar mui-bar-nav" style="background-color: rgba(221, 221, 221, 0);z-index: 99999;">  

        <h1 class="mui-title" style="color: #ffffff;">二维码扫描</h1>  
        <span class="mui-icon mui-icon-spinner-cycle mui-spin mui-pull-right" id="turnTheLight"></span>  
    </header>  

    <div id="bcid">  
        <!--盛放扫描控件的div-->  
    </div>  

    <div style="background-color: rgba(221, 221, 221, 0);z-index: 99999" class="mui-bar mui-bar-footer" style="padding: 0px;">  
        <div class="fbt" onclick="scanPicture();">从相册选择二维码</div>  
        <div class="fbt mui-action-back">取  消</div>  
    </div>  

    <script type="text/javascript">  
        var height = window.innerHeight + 'px'; //获取页面实际高度    
        var width = window.innerWidth + 'px';  
        document.getElementById("bcid").style.height = height;  
        document.getElementById("bcid").style.width = width;  

        scan = null; //扫描对象    
        mui.plusReady(function() { //通过mui初始化扫描  
            mui.init();  
            setTimeout("startRecognize()", 300)  

        });  

        function startRecognize() { //开启扫描  
            try {  
                var filter;  
                //自定义的扫描控件样式    
                var styles = {  
                    frameColor: "#29E52C",  
                    scanbarColor: "#29E52C",  
                    background: "rgba(255,255,255,-20)"  
                }  
                //扫描控件构造    
                scan = new plus.barcode.Barcode('bcid', filter, styles);  
                scan.onmarked = onmarked;  
                scan.onerror = onerror; //扫描错误  
                scan.start();  
                //打开关闭闪光灯处理    
                var flag = false;  
                document.getElementById("turnTheLight").addEventListener('tap', function() {  
                    if(flag == false) {  
                        scan.setFlash(true);  
                        flag = true;  
                    } else {  
                        scan.setFlash(false);  
                        flag = false;  
                    }  
                });  
            } catch(e) {  
                mui.toast("出现错误啦:\n" + e)  
            }  
        };  

        function onerror(e) { //错误弹框  
            alert(e);  
        };  

        function onmarked(type, result) { //这个是扫描二维码的回调函数,type是扫描二维码回调的类型  
            var text = '';  
            switch(type) { //QR,EAN13,EAN8都是二维码的一种编码格式,result是返回的结果  
                case plus.barcode.QR:  
                    text = 'QR: ';  
                    break;  
                case plus.barcode.EAN13:  
                    text = 'EAN13: ';  
                    break;  
                case plus.barcode.EAN8:  
                    text = 'EAN8: ';  
                    break;  
            }   
            smresult(result);  
        };  

        // 从相册中选择二维码图片     
        function scanPicture() { //可以直接识别二维码图片  
            plus.gallery.pick(function(path) {  
                plus.barcode.scan(path, onmarked, function(error) {  
                    //plus.nativeUI.alert("无法识别此图片");  
                    mui.toast("无法识别此图片");  
                });  
            }, function(err) {  
                plus.nativeUI.alert("Failed: " + err.message);  
            });  
        }  
        //关闭扫码页面  
        function closeSm() {  
            scan.close();  
            plus.webview.currentWebview().close('none');  
        }  
        //结果处理  
        function smresult(result) {  
            var bType = getBarcodeType(result);//二维吗类型  
            var type = localStorage.getItem("type");  
            if(type == "addfile") {  
                //添加档案扫码处理  

                if(bType==TMLX_JDCDA||bType==TMLX_JSZDA) {  
                    var tmnr = result;  
                    tmnr = getUrlp(tmnr);  
                    var params = "{" + "'method':'getTmxx'," + "'tmnr':" + "'" + tmnr + "'" + "}"  
                    var datajson = eval('(' + getData(params) + ')');  
                    var str = '<li><input class="file-num" value="' + datajson.obj.FILE_NUMBER + '" type="text"   /><i onclick="remove(this)">╳</i></li>'  
                    var wn = plus.webview.currentWebview(); //获取当前窗口的WebviewObject对象,即B   
                    var wvA = wn.opener(); //获取当前窗口的创建者,即A    
                    wvA.evalJS("addNew('" + str + "')"); //执行父窗口中的方法  A中的addNew方法    
                    plus.webview.currentWebview().close(); //扫码成功,关闭当前webview  
                } else {  
                    mui.toast("请扫描档案二维码")  
                    scan.start();  
                }  
            } else if(type == "getgezi") {  
                //扫码格子获取格子信息  
                if(bType==TMLX_JDCDA||bType==TMLX_JSZDA) {  
                gezism(result);  
                var wn = plus.webview.currentWebview(); //获取当前窗口的WebviewObject对象,即B   
                var wvA = wn.opener(); //获取当前窗口的创建者,即A    
                wvA.evalJS("addGeZi('" + str + "')"); //执行父窗口中的方法  A中的addNew方法    
                plus.webview.currentWebview().close(); //扫码成功,关闭当前webview  
                localStorage.setItem("ifFrist", "none"); //设置不是首次调用  
                }else{  
                    mui.toast("请扫描格子二维码")  
                    scan.start();  
                }  
            } else if(type == "sys") {  

                if(bType == TMLX_GEZI) {  
                    /**条码类型:格子*/  
                    var btnArray = ['取消', '确认'];  
                    mui.confirm("是否进行入库操作?", "提示", btnArray, function(e) {  
                        if(e.index == 1) {  

                            localStorage.setItem("ifFrist", "none"); //设置不是首次调用避免重复扫码  
                            localStorage.setItem("sysSign", "true");  
                            var str =gezism(result);  
                            localStorage.setItem("str", str);  
                            var webview = mui.openWindow({  
                                url: "../rk/rk.html",  
                                id: "rk.html",  
                                waiting: {  
                                    autoShow: false //自动显示等待框,默认为true  
                                },  
                                createNew: true  
                            });  
                            setTimeout("plus.webview.currentWebview().close()", 300)//扫码成功,关闭当前webview  

                        } else {  
                            scan.start();  
                        }  
                    });  
                } else if(bType == TMLX_JDCDA) {  
                    /**条码类型:机动车档案*/  
                    alert("条码类型:机动车档案");  
                    scan.start();  
                } else if(bType == TMLX_JSZDA) {  
                    /**条码类型:驾驶证档案*/  
                    alert("条码类型:驾驶证档案");  
                    scan.start();  
                } else if(bType == TMLX_DAG) {  
                    /**条码类型:档案柜*/  
                    alert("条码类型:档案柜");  
                    scan.start();  
                }  

            }  

        }  
        //格子扫码操作  
        function gezism(result) {  
            var tmnr = result;  
            tmnr = getUrlp(tmnr);  
            var params = "{" + "'method':'getTmxx'," + "'tmnr':" + "'" + tmnr + "'" + "}"  
            var datajson = eval('(' + getData(params) + ')');  
            //获取格子最大序号  
            var param2 = "{" + "'method':'getDaccxh'," + "'gzcode':" + "'" + datajson.obj.GZCODE + "'" + "}"  
            var dataxh = eval('(' + getData(param2) + ')');  
            var str = '<li><i>编码:' + datajson.obj.GZCODE + '</i><i>已存数:' + dataxh.obj.xh + '</i></li>';  
            str += '<li><i>行:' + datajson.obj.ROS + '</i><i>列:' + datajson.obj.COLS + '</i><i>面:' + datajson.obj.ASPECT + '</i></li>'  
            localStorage.setItem("gzcode", datajson.obj.GZCODE); //gz保存code  
            return str;  
        }  
    </script>  
</body>  

</html>

收起阅读 »