我的总结

PHP字符串处理函数

addcslashes — 为字符串里面的部分字符添加反斜线转义字符
addslashes — 用指定的方式对字符串里面的字符进行转义
bin2hex — 将二进制数据转换成十六进制表示
chop — rtrim() 的别名函数
chr — 返回一个字符的ASCII码
chunk_split — 按一定的字符长度将字符串分割成小块
convert_cyr_string — 将斯拉夫语字符转换为别的字符
convert_uudecode — 解密一个字符串
convert_uuencode — 加密一个字符串

count_chars — 返回一个字符串里面的字符使用信息
crc32 — 计算一个字符串的crc32多项式
crypt — 单向散列加密函数
echo — 用以显示一些内容
explode — 将一个字符串用分割符转变为一数组形式
fprintf — 按照要求对数据进行返回,并直接写入文档流
get_html_translation_table — 返回可以转换的HTML实体
hebrev — 将Hebrew编码的字符串转换为可视的文本
hebrevc — 将Hebrew编码的字符串转换为可视的文本
html_entity_decode — htmlentities ()函数的反函数,将HTML实体转换为字符
htmlentities — 将字符串中一些字符转换为HTML实体
htmlspecialchars_decode —htmlspecialchars()函数的反函数,将HTML实体转换为字符
htmlspecialchars — 将字符串中一些字符转换为HTML实体
implode — 将数组用特定的分割符转变为字符串
join — 将数组转变为字符串,implode()函数的别名
levenshtein — 计算两个词的差别大小
localeconv — 获取数字相关的格式定义
ltrim — 去除字符串左侧的空白或者指定的字符
md5_file — 将一个文件进行MD5算法加密
md5 — 将一个字符串进行MD5算法加密
metaphone — 判断一个字符串的发音规则
money_format — 按照参数对数字进行格式化的输出
nl_langinfo — 查询语言和本地信息
nl2br — 将字符串中的换行符“\n”替换成“

number_format — 按照参数对数字进行格式化的输出
ord — 将一个ASCII码转换为一个字符
parse_str — 把一定格式的字符串转变为变量和值
print — 用以输出一个单独的值
printf — 按照要求对数据进行显示
quoted_printable_decode — 将一个字符串加密为一个8位的二进制字符串
quotemeta — 对若干个特定字符进行转义
rtrim — 去除字符串右侧的空白或者指定的字符
setlocale — 设置关于数字,日期等等的本地格式
sha1_file — 将一个文件进行SHA1算法加密
sha1 — 将一个字符串进行SHA1算法加密
similar_text — 比较两个字符串,返回系统认为的相似字符个数
soundex — 判断一个字符串的发音规则
sprintf — 按照要求对数据进行返回,但是不输出
sscanf — 可以对字符串进行格式化
str_ireplace — 像str_replace()函数一样匹配和替换字符串,但是不区分大小写
str_pad — 对字符串进行两侧的补白
str_repeat — 对字符串进行重复组合
str_replace — 匹配和替换字符串
str_rot13 — 将字符串进行ROT13加密处理
str_shuffle — 对一个字符串里面的字符进行随机排序
str_split — 将一个字符串按照字符间距分割为一个数组
str_word_count — 获取字符串里面的英文单词信息
strcasecmp — 对字符串进行大小比较,不区分大小写
strchr — 通过比较返回一个字符串的部分strstr()函数的别名
strcmp — 对字符串进行大小比较
strcoll – 根据本地设置对字符串进行大小比较
strcspn — 返回字符连续非匹配长度的值
strip_tags — 去除一个字符串里面的HTML和PHP代码
stripcslashes — 反转义addcslashes()函数转义处理过的字符串
stripos — 查找并返回首个匹配项的位置,匹配不区分大小写
stripslashes — 反转义addslashes()函数转义处理过的字符串
stristr — 通过比较返回一个字符串的部分,比较时不区分大小写
strlen — 获取一个字符串的编码长度
strnatcasecmp — 使用自然排序法对字符串进行大小比较,不区分大小写
strnatcmp — 使用自然排序法对字符串进行大小比较
strncasecmp — 对字符串的前N个字符进行大小比较,不区分大小写
strncmp — 对字符串的前N个字符进行大小比较
strpbrk — 通过比较返回一个字符串的部分
strpos — 查找并返回首个匹配项的位置
strrchr — 通过从后往前比较返回一个字符串的部分
strrev — 将字符串里面的所有字母反向排列
strripos — 从后往前查找并返回首个匹配项的位置,匹配不区分大小写
strrpos – 从后往前查找并返回首个匹配项的位置
strspn — 匹配并返回字符连续出现长度的值
strstr — 通过比较返回一个字符串的部分
strtok — 用指定的若干个字符来分割字符串
strtolower — 将字符串转变为小写
strtoupper –将字符串转变为大写
strtr — 对字符串比较替换
substr_compare — 对字符串进行截取后的比较
substr_count — 计算字符串中某字符段的出现次数
substr_replace — 对字符串中的部分字符进行替换
substr — 对字符串进行截取
trim — 去除字符串两边的空白或者指定的字符
ucfirst — 将所给字符串的第一个字母转换为大写
ucwords — 将所给字符串的每一个英文单词的第一个字母变成大写
vfprintf — 按照要求对数据进行返回,并直接写入文档流
vprintf — 按照要求对数据进行显示
vsprintf — 按照要求对数据进行返回,但是不输出
wordwrap — 按照一定的字符长度分割字符串

  • 有很好的开源意识,开放平台思想
  • Libraries for developersV3.39:众多开源效果集合–>国外–>只是提供了地址
  • android开源项目汇总:众多开源效果集合–>国人–>只是提供了地址
  • baseAnimation:众多开源效果–>针对动画效果–>国人–>开源的.需要效果的时候.要自行去找对应的代码
  • http://www.23code.com/–>开源项目集合网站
  • http://a.code4app.com/–>开源项目集合网站
  • 一些demo的集合–>5000
  • 深度理解,广度知道

###Volley

  • 回忆xutils:快速开发型框架,DbUtils(orm),ViewUtils(ioc),HttpUtils,BitmapUtils
  • 其他的快速开发型框架:andBase,thinkandroid,loonandroid,dhroid
  • orm:对象关系型映射
    • db:create table t_table(_id integer primary key autoincret…);
    • insert–>save(obj)
  • ioc:控制反转
    • Obj obj = new Obj();
    • 对象的实例化,不用new关键字就可以了吧.
  • 为什么要讲volley?
    • 因为它是google出的,google 在2013 i/o大会上提出来的.
    • 而且在几个项目里面已经看到了它的身影
  • google公司为什么会去搞一个volley框架?
      1. 用户开启一个activity,然后加载网络,这个时候.如果用户点击了finish按钮.activity被销毁了–>网络请求和activity的生命周期是应该联动起来的.
      1. listview加载图片的情况比较多.如果用户快速的去滑动listview–>getView->快速的加载图片,用户停止操作的时候.其实真正现实的图片最多就几张—>图片应该缓存起来(内存 +本地 )
      1. 如果用户打开了一个activity,用户旋转了一下屏幕.activity会旋转–>生命周期重走了–>网络请求缓存
      1. 之前我们的网络请求,httpurlconnection,httpclient,asynctask(api)–>android sdk–>封装性不够好.1000个开发者就有1000种使用方式–>不够统一
      1. 理念很容易理解,是开源的.
  • volley是啥?
    • 是一种通信框架,和xutils中的HttpUtils,BitmapUtils

###Volley两个核心类

  • Request:一个请求
    • StringRequest:请求的时候直接回来一个String
    • JsonObjectRequest:请求的时候直接回来一个JsonObject
    • JsonArrayRequest:请求的时候直接回来一个JsonArray
    • ImageRequest:请求的时候直接回来一个Bitmap
    • 自定义请求:一会我们会结合gson
  • ImageLoader:图片的加载器
  • NetWorkImageView:继承了imageView,对ImageView进行了拓展
  • RequestQueue:请求队列.
    ###一步一步学习

###JsonObject取值

  • String origin = response.getString(“origin”);// 方式一
    • 这个如果没有对应的key会抛异常.需要异常处理
  • String origin = response.optString(“origin”);// 方式二
    • 这个如果没有对应的key不会抛异常.会返回一个默认值
    • optString:默认值””
    • optInt:默认值 0
    • 比如有的实体bean属性很多.我们不喜欢去建议对应的XXX.class的时候.可以使用JsonObject里面的这个方法;
      ###图片
  • 大图片的处理:
    • 大图片处理的核心
    • 核心类:BitmapFactory.Options
    • 核心方法:
      • decodeOptions.inJustDecodeBounds = true;–>得到图片的宽度以及高度,不需要把图片加载到内存 10M
      • decodeOptions.inJustDecodeBounds = false;–>真正去加载图片
      • decodeOptions.inSampleSize–>采样率–>不同的框架有不同的核心算法
        • 特点:2 4 8 –>取值最好使用2的指数
  • 图片的加载
  • 图片的缓存

###框架找SampleSize的方式

  1. volley

    static int findBestSampleSize(
        int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
    double wr = (double) actualWidth / desiredWidth;
    double hr = (double) actualHeight / desiredHeight;
    double ratio = Math.min(wr, hr);
    float n = 1.0f;
    while ((n * 2) <= ratio) {
        n *= 2;
    }
    return (int) n;
    }
    
  2. Xutils

     public static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
    
    if (width > maxWidth || height > maxHeight) {
        if (width > height) {
            inSampleSize = Math.round((float) height / (float) maxHeight);
        } else {
            inSampleSize = Math.round((float) width / (float) maxWidth);
        }
    
        final float totalPixels = width * height;
    
        final float maxTotalPixels = maxWidth * maxHeight * 2;
    
        while (totalPixels / (inSampleSize * inSampleSize) > maxTotalPixels) {
            inSampleSize++;
        }
    }
    return inSampleSize;
    

    }

  3. uil_imageLoader

    public static int computeMinImageSampleSize(ImageSize srcSize) {
    final int srcWidth = srcSize.getWidth();
    final int srcHeight = srcSize.getHeight();
    final int targetWidth = maxBitmapSize.getWidth();
    final int targetHeight = maxBitmapSize.getHeight();
    
    final int widthScale = (int) Math.ceil((float) srcWidth / targetWidth);
    final int heightScale = (int) Math.ceil((float) srcHeight / targetHeight);
    
    return Math.max(widthScale, heightScale); // max
    }
    
    public static int computeImageSampleSize(ImageSize srcSize, ImageSize targetSize, ViewScaleType viewScaleType,
        boolean powerOf2Scale) {
    final int srcWidth = srcSize.getWidth();
    final int srcHeight = srcSize.getHeight();
    final int targetWidth = targetSize.getWidth();
    final int targetHeight = targetSize.getHeight();
    
    int scale = 1;
    
    switch (viewScaleType) {
        case FIT_INSIDE:
            if (powerOf2Scale) {
                final int halfWidth = srcWidth / 2;
                final int halfHeight = srcHeight / 2;
                while ((halfWidth / scale) > targetWidth || (halfHeight / scale) > targetHeight) { // ||
                    scale *= 2;
                }
            } else {
                scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // max
            }
            break;
        case CROP:
            if (powerOf2Scale) {
                final int halfWidth = srcWidth / 2;
                final int halfHeight = srcHeight / 2;
                while ((halfWidth / scale) > targetWidth && (halfHeight / scale) > targetHeight) { // &&
                    scale *= 2;
                }
            } else {
                scale = Math.min(srcWidth / targetWidth, srcHeight / targetHeight); // min
            }
            break;
    }
    
    if (scale < 1) {
        scale = 1;
    }
    scale = considerMaxTextureSize(srcWidth, srcHeight, scale, powerOf2Scale);
    
    return scale;
    

    }

###内存缓存

  • 1.内存缓存的核心:
    • 存:就有很多的考虑
    • 取:只需要知道唯一的key就可以了
  • 2.选择什么样的存储结构/容器/集合?Map
  • 3.4种引用级别什么意思?
    • 强引用:我们平时使用的集合(arraylist,hashmap,hashset),即使内存oom,也不会去回收对象;
    • 软应用:使用SoftRefrence去包装一个对象,内存不足的时候去回收对象,尽量保证不oom
    • 弱应用:基本没有用过
    • 虚引用:形同虚设,同样没有用过
  • 4.删除策略/算法,我们定义的存储结构,不能继续缓存图片的时候.需要进行清理
    • LRU:最近最少使用,Least Recently Used,其实就是按照访问顺序排序
    • 删除使用次数最少的:
    • 删除占用体积最大:
    1. 在很久之前(2,3年)前做图片的缓存基本都是使用软应用,但是在2.3之后.google文档明确指出了软应用做缓存的一些不足.建议我们使用LruCache.class;
  • 6.举例说明删除策略的使用场景
    • LRU:电影海报图删除策略–>和时间有关系(时效性)
    • 删除使用次数最少的:–>和时间没有关系而且大小差不多
    • 删除占用体积最大:空间比较宝贵的情况

###LruCache的使用:

一个工具方法,提供了基于Lru缓存策略强引用的内存缓存,存储结构使用的LinkedHashmap

  • LinkedHashmap使用

    • LinkedHashmap和Hashmap区别:在构造方法里面多了3个参数
    • 3个参数的意义:
      • initialCapacity:初始化容器大小 16
      • loadFactor:负载因子
      • accessOrder:
        • true:LinkedHash内部会排序–>按照访问顺序排序–>这个也是为什么LruCache使用LinkedHashmap做存储结构的原因
        • false:按照插入顺序去排序
  • LruCache在什么地方可以找到?

    • 在高版本的sdk里面有.
    • 在v4包中有提供.
  • LruCache的使用
    1. 告知缓存的具体大小
    2. 覆写sizeOf方法,具体大小需要和我们定义的maxsize单位统一
      ###网络请求的取消
  • httpclient:

    DefaultHttpClient httpClient = new DefaultHttpClient();
    ClientConnectionManager connectionManager = httpClient.getConnectionManager();// 拿到连接管理器
    connectionManager.shutdown();
    
  • httpurlconnection:
  • volley:多级别取消
    • 取消某一个请求:
    • 取消请求的队列:
//2. 创建RequestQueue
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
//3. 发起请求
queue.add(stringRequest);
//取消单个请求
stringRequest.cancel();//取消一个请求
//取消所有请求
queue.cancelAll(null);//取消请求队列里面所有的方法
//取消置顶tag的请求
queue.cancelAll("tag1");//取消tag为tag1的一个请求
//请求添加tag-->tag的目的就是为了反查
stringRequest.setTag("tag1");
//两个不同的请求可以设置同一个tag
stringRequest.setTag("tag1");
//    stringRequest1.setTag("tag1");
  • xutils:xutils其实也是封装的httpclient,所以网络请求取消的方式和httpClient一样
  • 生命周期的联动

    StringRequest req1 = null;
    StringRequest req2 = null;
    StringRequest req3 = null;
    StringRequest req4 = null;
    StringRequest req5 = null;
    
    req1.setTag(this.getClass().getSimpleName());
    req2.setTag(this.getClass().getSimpleName());
    req3.setTag(this.getClass().getSimpleName());
    req4.setTag(this.getClass().getSimpleName());
    req5.setTag(this.getClass().getSimpleName());
    
    // 取消对应activity里面所有的请求
    RequestQueue queue = VolleyTools.getInstance(MainActivity.this).getQueue();
    queue.cancelAll(this.getClass().getSimpleName());// MainActivity
    

###架构

  • b/s架构:绘图说明

  • mvc:设计思想

    • M:model javaBean domain
    • V:view xml view adapter
    • C:Ctroller Activity Fragment
  • mvp:设计思想

    • M:model
    • V:View
    • P:Presenter
  • 四层架构:自我总结

    • 数据提供层–>dataProvider:提供数据
    • 数据持久层–>data persistent–>sqlite ,sp,file
    • 业务逻辑层–>servcie logic
    • ui展现层

###gzip

一种压缩格式,一种压缩方式,可以对网络传输的数据进行压缩.减少网络传输的大小

  • 为什么需要压缩?

    • 减少体积,提高传输速度,提高用户体验
  • 浏览器发送器请求的过程?

    • 1.发送请求头:Accept-Encoding:gzip
    • 2.服务器压缩数据,返回数据,在响应头里面添加Content-Encoding:gzip
    • 3.客户端,根据Content-Encoding这个响应头,对应解压
      • 有Content-Encoding:gzip–>gzip解压
      • 没有Content-Encoding:gzip–>标准解压
  • app使用gzip压缩
    • 返回的json/xml(文本信息)其实就是个特殊的网页,其实也是可以进行gzip压缩

###gzip压缩效果

通过数据,我们得知,文本的压缩率,大概可以达到70%左右.压缩率很高;

###gzip压缩的实现

try {
    boolean isGzip = false;
    //1.创建httpclient
    DefaultHttpClient httpClient = new DefaultHttpClient();
    //2.创建get请求
    HttpGet get = new HttpGet("http://httpbin.org/gzip");
    //① 添加请求头 Accept-Encoding:"gzip, deflate"
    get.addHeader("Accept-Encoding", "gzip");
    //3.执行请求
    HttpResponse response = httpClient.execute(get);
    if (response.getStatusLine().getStatusCode() == 200) {
        //② 得到响应头,Content-Encoding:"gzip"
        Header[] headers = response.getHeaders("Content-Encoding");
        for (Header header : headers) {
            if (header.getValue().equals("gzip")) {//后台server把数据进行了gzip压缩
                isGzip = true;
            }
        }
        String result = "";
        HttpEntity entity = response.getEntity();
        //③根据是否使用gzip压缩.采取不同的解压方式
        if (isGzip) {
            //④进行gzip的解压
            GZIPInputStream in = new GZIPInputStream(response.getEntity().getContent());
            //in-->string
            result = convertStreamToString(in);
        } else {
            //4.打印结果
            result = EntityUtils.toString(entity);
        }
        System.out.println("result:" + result);
    }
} catch (Exception e) {
    e.printStackTrace();
}

###测试请求的地址

http://httpbin.org

###常见的content-type

  • application/x-www-form-urlencoded:表单,key-value
  • multipart/form-data:二进制,file
  • application/json :json,虽然有的服务器直接用text/plain这个请求头没有任何问题.但是很多服务器,必须需要application/json,明确的说.如果是返回json,一定加上application/json,不要用默认的.实际开发遇到了几次这样的问题.或者说.加上这个请求头肯定是万无一失;
  • text/xml :xml
  • text/plain:普通文本,默认类型

###模拟请求插件restClient的使用

这个是firefox上的一个插件,对应chrome浏览器叫做postman,这个插件主要用作和服务器开发人员联调协议;

  • key-value:
    • 1.添加head–>Content-Type
    • 2.传递参数:key=value&key=value
  • jsonString
    • 1.添加head
    • 2.传递参数:jsonString

###编码.数字摘要.加密.解密

  • 编码:Base64,urlEncoder/urlDecoder

    • urlEncoder:地址栏不允许中文,传递一些特殊字符 & ?

      String url = "http://www.baidu.com?serarch=\"哈哈\"&key=value";//& ? 
      //URLEncoder encode
      String encode = URLEncoder.encode(url);
      System.out.println(encode);
      //URLDecoder decode
      String decode = URLDecoder.decode(encode);
      System.out.println(decode);
      //没有经过encode的字符串.直接decode,会原样输出
      String decode2 = URLDecoder.decode(url);
      System.out.println(decode2);
      
    • Base64:把一些对象转换成string,用处:传输的时候不要明文传输

      • 上传图片,上传语音
      • 如何把一个map存到sp–>Base64支持把byte[]–>String,只需把对象先转换成byte[]就可以存到sp中

        ImageView iv = (ImageView) findViewById(R.id.iv);
        //1.得到bitmap
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
        //2.bitmap-->byte[]
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        bitmap.compress(CompressFormat.PNG, 100, out);
        byte[] bitmapByteArr = out.toByteArray();
        //3.使用base64 byte[]--String--->上传到服务器
        String bitmapBase64String = Base64.encodeToString(bitmapByteArr, Base64.DEFAULT);
        
        //key-value jsonString
        
        //4.String-->byte[]
        byte[] bitmapByteArr2 = Base64.decode(bitmapBase64String, Base64.DEFAULT);
        //5.byte[]-->Bitmap -->完成图片的上传
        Bitmap bitmapPassed = BitmapFactory.decodeByteArray(bitmapByteArr2, 0, bitmapByteArr2.length);
        //6.设置图片到imageView
        iv.setImageBitmap(bitmapPassed);
        
  • 数字摘要:md5 sha1

    • md5:密码一般都是需要md5,不可逆,而且1kb的文件和1tb的文件.md5之后.得到的结果长度是一样;
    • md5作用:或者叫做数字摘要作用–>确定数据未被修改 文件的唯一性
    • 加盐: 就是在密码的前面加入一些特殊字符%^&&%^&
    • sha1:和md5算法不一样.作用一样
    • android support v4:v4包的版本冲突.就是根据sha1值判断
    • 秒传功能:其实也是根据文件的sha1
  • 加密/解密

  • 对称加密:只有一把密钥,如果密钥暴露,文件就会被暴露
    • des: Data Encryption Standard
    • aes: Advanced Encryption Standard
    • 特点:加密速度比较快.可以加密比较大的文件
  • 非对称加密:有两把钥匙(密钥对),公钥和私钥,公钥的话给别人.私钥自己保存,;
    • RSA
    • 特点:加密速度比慢一些,但是安全系数比较高
    • 秘钥对的话需要程序生成.不能我们自己定义
    • 加密/解密:公钥加密–>私钥解密
      • public static byte[] encryptByPublicKey(byte[] data, String publicKey)//公钥加密
      • public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)//私钥解密
    • 加密/解密:私钥加密–>公钥解密
      • public static byte[] encryptByPrivateKey(byte[] data, String privateKey)//私钥加密
      • public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)//公钥解密
    • 数字签名:确定数据来源的不可否认性,确定所属关系–>其实就是确定privatekey在哪里.
      • 签名:public static String sign(byte[] data, String privateKey)//只能使用私钥进行签名
      • 校验:public static boolean verify(byte[] data, String publicKey, String sign)
    • 公钥互换:两个人,两个结构,就是说两个密钥对的持有者相互的置换公钥

###sqlite db文件加密

  • 如果应用的数据很多是来源db文件–>核心数据
  • 聊天信息–>敏感数据
  • sqlitecipher
    • 使用它,应用程序体积会大很多.因为需要引入差不多6m的东西
    • 步骤:
      • 加入libs
      • 加入assets
      • 注意引擎的初始化

###sqlite 数据库表字段巧设计

  • 缓存bean的属性比较多–>数据库表的列字段比较—>很繁琐(代码可能需要不停的put put put)
  • 项目的初期,表字段可能增加,减少,以及修改–>都会修改表结构–>所以缓存的数据就没啥用
  • 解决方法,我们可以把相关的信息json化之后,保存它的jsonString就可以了

    db.execSQL("CREATE TABLE `" + TABLE_NAME_CINEMA_SIMPLE + "` ( `Id` integer primary key autoincrement, "//
    + "`cityId` varchar(10)," + //
    "`cinemaId` varchar(10)," + //
    " `cinemaSimpleInfo` varchar(400)," + //这里就是我们jsonString
    "`insertDate` varchar(10))");// /
    

###移动支付

用户使用移动的设备,完成对所购买商品或者服务的支付功能.远程支付(网上支付,短信支付),近场支付(刷卡,滴卡,pos机)

###apk集成支付功能

###常见的支付厂商

  • 支付宝:阿里公司,支付宝使用比较多.
  • 微信:腾讯公司,也是越来越多.
  • 易付宝:
  • 财付通:腾讯公司
  • 银联:不属于某一个公司
  • 百度钱包:百度
  • 支付宝钱包:阿里的.
  • 快钱:
  • ping++:整合了很多的支付平台

###支付难不难?

不难,都是属于第三方的东西.难度不大

###支付安不安全?

肯定是安全的.因为这些都是大公司的产品.都有自己的安全策略;

###做一个支付需要多久?

  • 项目评估
  • 支付宝:大概5分钟.
  • 银联支付:大概5分钟.
  • 微信支付:大概10分钟.

###支付流程_从生活出发
1.选择商品
2.选择支付方式
3.处理支付结果

###支付流程_从app开发角度(保证可以先完成功能)

  1. 拼接支付信息,post到服务器;–>request
    1. 支付信息包含支付方式
    2. 服务器:是我们自己的服务器
    3. 支付协议:http://mobileif.maizuo.com/version3/orderform/order?version=2
  2. 服务器返回支付串码;—>reponse

    请求的url(支付协议/确认订单协议):  http://mobileif.maizuo.com/version3/orderform/order?version=2
    请求方式:post
    post参数形式:jsonString
    输入参数:{"goodInfos":[{"goodCounts":"1","goodExtInfo":{},"goodIDs":"361","goodType":"1"}],"loginFlag":"0","mobile":"18682036558","orderId":"0","otherInfo":{"agentID":"0-maizuo","channelID":"31","clientID":"31"},"payDatas":{"discountInfo":{"activeID":"0","discountID":"0","discountPrice":""},"payInfo":[{"bankType":"7","payCount":"3200","payTicketCount":"1","payType":"1"}],"payPass":"","returnUrl":"","totalPrice":"3200"},"processPath":"1","sessionKey":"mqneaadqapkpkqshxvdj","userID":"200394160"}
    输出结果{"result":"ok","payExtInfo":{"alipayVerifyKey":"_input_charset=\"UTF-8\"&body=\"卖座网电子影票\"&it_b_pay=\"1h\"&notify_url=\"http%3A%2F%2Fpay.maizuo.com%2FmobileBack.htm\"&out_trade_no=\"201507238712113008\"&partner=\"2088411628331920\"&payment_type=\"1\"&seller_id=\"2088411628331920\"&service=\"mobile.securitypay.pay\"&subject=\"深圳金逸影城沙井店(2D通兑票1张)\"&total_fee=\"32.00\"&sign=\"M0O0Ej5J13A25SAWupc5a6vAGmJnblx2CvuWF2dwFGxMZ%2BxlRWmp%2F6ZDfI8Y%2FFJbjiEqE99MAsKh%0AfIBQqP4Y1TyNkbY0XixQFPgAAqsqwGqYJSDtqUFWRgje%2B8pI1KuxfPE3UcDZs4hxDZoP%2Bdof%2Bldf%0AKQmximUyqT5Crtwj1Ag%3D\"&sign_type=\"RSA\""},"bankType":"","userId":"200394160","resource":{"rel":"view","link":"/orderform/200394160/201507238712113008"},"payType":"7","payUrl":"","orderId":"201507238712113008","uniqueKey":"D5585vO8624915A11z","timeNow":"1437622208552"}
    
  3. 拿着支付串码,调用第三方服务,完成支付–>5分钟

  4. 处理支付结果
    1. 同步返回:支付后通知我们自己的apk
    2. 异步通知:支付后通知我们的server

###什么是支付串码

这个是老师自己定义的一个概念.其实就是第三步调用起第三方支付平台核心支付方法所需要的参数

###集成支付宝流程

  1. 我们自己要和支付宝签约(商户签约).–>运营
  2. 秘钥配置–>协助运营完成秘钥的配置(公钥互换),可能程序员会参与
  3. 集成支付宝–>必须是程序员去做.

    1. 下载sdk/demo/文档
    2. demo尝试的去运行
      1. 出现了错误:因为缺少运行必须的,DEFAULT_PARTNER,DEFAULT_SELLER,如果1,2步完成的话,我们在这个时候就可以有DEFAULT_PARTNER,DEFAULT_SELLER
    3. 开始集成–>参照移动快捷支付应用集成接入包支付接口接入与使用规则.pdf

      1. 添加jar,alipay.jar
      2. 添加lib,alipay_lib
      3. 添加了一个activity
      4. 添加了一些权限
      5. 调用支付的核心代码

        //    3.调用第三方服务,完成支付
        //获取Alipay对象,构造参数为当前Activity和Handler实例对象
        AliPay alipay = new AliPay(MainActivity.this, mHandler);
        //调用pay方法,将订单信息传入
        //同步返回    取消操作  支付成功  支付失败(网络异常)
        String payResult = alipay.pay(alipayVerifyKey);
        
      6. 处理支付结果—>支付宝处理支付结果用的handler机制

        /**---------------demo里面处理支付结果的代码---------------**/
        
        /*Result result = new Result((String) msg.obj);
        switch (msg.what) {
        case RQF_PAY:
        case RQF_LOGIN: {
            Toast.makeText(ExternalPartner.this, result.getResult(), Toast.LENGTH_SHORT).show();
        
        }
            break;
        default:
            break;
        }
        */
        /**---------------老师实际开发处理支付结果的代码---------------**/
        
        /*Result.sResult = (String) msg.obj;
        Logger.i(TAG, "strRet:" + Result.sResult);
        try {
            String errorMsg = Result.getPayResult();
            Logger.i(TAG, "errorMsg:" + errorMsg);
            if (!"".equals(errorMsg)) {
                Toast.makeText(getApplicationContext(), errorMsg, 0).show();
                if ("操作成功".equals(errorMsg)) {
                    payOk();//支付成功可以调到订单界面
                } else {
                    payFail();//可以弹出对话框进行重复支付
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (!PayActivity.this.isFinishing()) {
                BaseHelper.showDialog(PayActivity.this, "提示", Result.sResult + ",如有疑问请联系卖座客服:4001808400", R.drawable.infoicon);
            }
        }
        

        }
        };*/

###支付宝demo分析

  • 查看demo发现他的支付串码,是在客户端生成的.这个和老师所讲的.支付串码由服务器生成.有出入;
  • 为了不暴露我们privatekey,我们应该把生成支付串码的过程交给我们的服务器

    /**---------------生成支付串码的过程  begin---------------**/
    Log.i("ExternalPartner", "onItemClick");
    String info = getNewOrderInfo(position);
    //其实下面的操作应该是server端去完成.不然我们会暴露privatekey---begin---add_by_billy
    //所有我们会把info的具体内容用jsonString的形式.post给server进行签名.然后返回签名后的结果---add_by_billy
    String sign = Rsa.sign(info, Keys.PRIVATE);
    sign = URLEncoder.encode(sign);
    info += "&sign=\"" + sign + "\"&" + getSignType();
    Log.i("ExternalPartner", "start pay");
    // start the pay.
    Log.i(TAG, "info = " + info);
    //其实下面的操作应该是server端去完成.不然我们会暴露privatekey---end---add_by_billy
    final String orderInfo = info;
    /**---------------生成支付串码的过程  end---------------**/
    

    ###支付串码_老师自己定义的一个概念

    支付串码就是调用第三方应用的时候需要的一些核心的参数

###银联支付

  • 银联支付,就只需要一个交易流水号就可以,而且看代码比较简单,重点是,银联强制要求生产支付串码的过程必须交给我们的服务端
  • 集成形式
    • 内嵌apk形式:就是把一个apk放到我们的assets目录下面–>老的方式
    • 新版本so库形式:在libs下面就有很多的so库.已经不需要在assets目录下面放置apk
  • 模式:
    • 测试模式:银联会给我们提供一个测试环境+提供了一个银联的账号/密码
    • 正式模式:就必须使用真实的账号/密码
  • 运行demo看效果:
  • 集成步骤:

    • 1.添加libs里面相关的东西;
    • 2.添加activity配置

      <activity
      android:name="com.unionpay.uppay.PayActivityEx"
      android:configChanges="orientation|keyboardHidden|screenSize"
      android:excludeFromRecents="true"
      android:label="@string/app_name"
      android:screenOrientation="portrait"
      android:windowSoftInputMode="adjustResize" />
      <activity
          android:name="com.unionpay.uppay.PayActivity"
          android:configChanges="orientation|keyboardHidden|screenSize"
          android:excludeFromRecents="true"
          android:screenOrientation="portrait" />
      
    • 3.添加权限

        <!-- uupay -->
        <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
* 4.调用核心的支付方法

        //拿着支付串码
        System.out.println("alipayVerifyKey:" + alipayVerifyKey);
        //    3.调用第三方服务,完成支付
        // “00” – 银联正式环境
        // “01” – 银联测试环境,该环境中不发生真实交易
        //tn 交易流水号  
        UPPayAssistEx.startPayByJAR(MainActivity.this, PayActivity.class, null, null,
                alipayVerifyKey, "00");
* 5.处理支付结果


        /**---------------银联处理支付结果---------------**/
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        /*************************************************
         * 
         * 步骤4:处理银联手机支付控件返回的支付结果
         * 
         ************************************************/
        if (data == null) {
            return;
        }

        String msg = "";
        /*
         * 支付控件返回字符串:success、fail、cancel 分别代表支付成功,支付失败,支付取消
         */
        String str = data.getExtras().getString("pay_result");
        if (str.equalsIgnoreCase("success")) {
            msg = "支付成功!";
        } else if (str.equalsIgnoreCase("fail")) {
            msg = "支付失败!";
        } else if (str.equalsIgnoreCase("cancel")) {
            msg = "用户取消了支付";
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("支付结果通知");
        builder.setMessage(msg);
        builder.setInverseBackgroundForced(true);
        // builder.setCustomTitle();
        builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.create().show();
        }

###微信支付

  • 直接运行demo,发现最后提示错误,发现工程下面有一个debug.keystore
  • 想要运行.可以如下操作

    • 自定义keystore
    • 或者直接导出的时候用工程下面的debug.keystore去签名
  • 微信支付的安全策略之一:必须包名和keystore签名需要一致

  • demo里面定义的步骤
    • 一、获取 access_token
    • 二、生成预支付订单,需要用到第一步的access_token,得到的是prepayId
    • 三、调起微信支付
    • 四、处理支付结果
    • 这个时候一看.感觉微信支付很难.但是我们看到demo里面这样的一句话注意:不能hardcode在客户端,建议genPackage这个过程由服务器端完成,所以,其实我们的微信支付,一、二步骤为了安全起见应该交给Server
  • 实际开发,只需关心3,4步就可以

    • 三、调起微信支付

      /**
       * @author Administrator
       * 支付的时候真正关心的数据
       * 这个对象是我自己封装的.和微信支付的sdk没有关系
       */
      public class WXPayData {
      private String sign_method;
      private String timestamp;
      private String noncestr;
      private String partnerid;
      private String app_signature;
      private String prepayid;
      private String package1;
      private String appid;
      }
      
      //核心支付方法
      private void sendPayReq(WXPayData info) {
      api = WXAPIFactory.createWXAPI(this, info.getAppid());
      PayReq req = new PayReq();
      req.appId = info.getAppid();
      req.partnerId = info.getPartnerid();
      req.prepayId = info.getPrepayid();//预支付id
      req.nonceStr = info.getNoncestr();//32位内的随机串,防重发
      req.timeStamp = String.valueOf(info.getTimestamp());//时间戳,为 1970 年 1 月 1 日 00:00 到请求发起时间的秒数
      req.packageValue = info.getPackage1();
      req.sign = info.getApp_signature();
      // 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
      api.sendReq(req);
      

      }

    • 四、处理支付结果:微信支付支付的回调是在net.sourceforge.simcpux.wxapi.WXPayEntryActivity.class里面
@Override
public void onResp(BaseResp resp) {
Log.d(TAG, "onPayFinish, errCode = " + resp.errCode);

if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(R.string.app_tip);
    builder.setMessage(getString(R.string.pay_result_callback_msg, String.valueOf(resp.errCode)));
    builder.show();
}
}

###安全码策略

安全码的组成规则为:Android签名证书的sha1值+“;”+packagename(即:数字签名+分号+包名)

  • 作用:确定apk的唯一性