Skip to content

钩子专属

  • 首页
  • 安卓技术
  • 安卓教程

All posts by oshook

  • 首页   /  
  • 作者: oshook
  • ( 页面4 )
安卓技术 6 月 21,2023

接入微信支付

接入微信支付相对支付宝支付要麻烦些,它和包名,签名有关。更让人难以理解的是类名和类所在的包名都是规定好的,不能改的,一改你就调不起微信支付。

官方文档地址

https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3

包名和应用签名的获取

包名:build.gradle文件中的applicationId而不是AndroidManifest.xml中的package。以后凡是说到包名都是applicationId。

应用签名的获取:因为项目的app都是用360加固的,360加固上在加固应用时在任务详情可以看到,签名md5就是,它是大写的,你弄成小写就是了
如下图:

}AVUQMP~Z6BS1~TA0K@H%5P.png

万一填错了也可以改的,好像要等1天才能修改成功

依赖以及相关配置

在app下build.gradle文件中,添加如下依赖即可

    dependencies {

compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'

}

在Application中初始化先向微信注册您的APPID

private void initWxPay() {
    //初始化微信api
    wxapi = WXAPIFactory.createWXAPI(this, WxPayUtils.getWxAppId(), false);
    //注册appid
    wxapi.registerApp(WxPayUtils.getWxAppId());
}

调起微信支付

示例代码:

public static void wxPay(Context context, final String prepqyId) {
    if (MyApplication.getWxapi().isWXAppInstalled()) {
        Thread payThread = new Thread() {
            @Override
            public void run() {
                PayReq request = new PayReq();
                request.appId = WxPayUtils.getWxAppId();
                request.partnerId = WxPayUtils.getWxMchId();
                request.prepayId = prepqyId;
                request.packageValue = "Sign=WXPay";
                request.nonceStr = WxPayUtils.getNumSmallLetter();
                request.timeStamp = (System.currentTimeMillis() / 1000) + "";
                SortedMap map = new TreeMap();
                map.put("appid", request.appId);
                map.put("partnerid", request.partnerId);
                map.put("prepayid", request.prepayId);
                map.put("package", request.packageValue);
                map.put("noncestr", request.nonceStr);
                map.put("timestamp", request.timeStamp);
                request.sign = WxPayUtils.createMD5Sign(map);
                MyApplication.getWxapi().sendReq(request);
            }
        };
        payThread.start();
    } else {
        ToastUtils.show(context.getString(R.string.wx_unInstalled));
    }


}

public static String createMD5Sign(SortedMap map) {
    StringBuilder sb = new StringBuilder();
    Set es = map.entrySet();
    Iterator it = es.iterator();
    while (it.hasNext()) {
        Map.Entry entry = (Map.Entry) it.next();
        String k = (String) entry.getKey();
        String v = (String) entry.getValue();
        sb.append(k + "=" + v + "&");
    }
    String params = sb.append("key=" + getWxSignKey()).substring(0);
    String sign = MD5Encode(params, "utf8");
    sign = sign.toUpperCase();
    return sign;
}

其中getWxAppId是申请的appId,getWxMchId是商户号,在微信支付后面查看详情中可查看
createMD5Sign()方法是接口给的,就是和接口一样的,可以问下服务器端同事。其中getWxsignKey也是接口给或者是申请微信支付的人弄的,它是用来加密各个请求的参数的,它必须和接口用的是一样的。这个我也不知道在那查看

处理支付结果回调

建WXPayEntryActivity类,目录结构示例如下:

)C1Z(@OA}PMXKH)8VM8X_07.png
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {


private IWXAPI api;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    api = MyApplication.getWxapi();
    api.handleIntent(getIntent(), this);
}

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
    api.handleIntent(intent, this);
}

@Override
public void onReq(BaseReq req) {
}

@Override
public void onResp(BaseResp resp) {

    if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
    //errCode为0是支付成功,其他都是失败
        if (resp.errCode == WxPayUtils.PAY_SUCCESS_CODE) {
            //支付成功
            LogUtils.v("wxpayy", "支付成功");
            //去后台查询订单结果
        } else {
            //支付失败
            LogUtils.v("wxpayy", "支付失败");
            LogUtils.v("wxpayy", resp.errCode + "/");
            //根据错误code排查问题
        }
    }
    finish();
}}

注意

resp.errCode为-1肯定是配置问题,不用怀疑

调不起微信支付问题排查

  1. 签名的文件是否和申请时的一致,debug时是否用上了签名文件
  2. appId,商户号,request.sign是否和接口用的一样
  3. WXPayEntryActivity建的目录结构是否正确,是否真的是该包名路径下建的,类名不能错

换包名该如何修改

1、其实很简单,WXPayEntryActivity类的目录得建对。如下图所示

7NHW7VRTZ9~9}(ZEK98SAFT.png

2、appId,商户号,request.sign得换新的
3、修改applicationId,修改签名文件

如果发现调不起微信支付或者修改包名之后有问题可以私信我

作者 oshook
安卓技术 6 月 21,2023

接入支付宝支付SDK

可以说支付宝支付接入是所有SDK最好接入的,没有之一。
客户端不用签名,也不用管包名,也不用管签名文件,就接口返回订单,把订单交给支付宝SDK调用就行,成功或者失败都在当前界面返回给你。你再去通知接口。

支付流程图

alipay.png

官方文档地址

!支付宝支付官方文档地址
按照文档说明接入SDK和相关配置,在这就不重复了

客户端支付关键代码===》支付接口的调用(调起支付弹框)

记住支付接口的调用必须在独立的非ui线程中执行,即需新开线程里面调用。可以想官方demo一样用new Thread方式。
下面我给出用Observable方式示例代码
在PayUtils中

/**
 * desc:支付宝支付
 * Created by congge on 2018/8/27 17:20
 * @param orderInfo 接口返回的订单
 **/
public static void aliPay(final Activity activity, final String orderInfo, final OrderListener orderListener) {
    Observable.just(orderInfo)
            .map(new Function() {
                @Override
                public String apply(String orderInfo) throws Exception {
                    //用户在商户app内部点击付款,是否需要一个loading做为在钱包唤起之前的过渡,这个值设置为true
                    return new PayTask(activity).pay(orderInfo, true);
                }

            })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Consumer() {
                @Override
                public void accept(String payResult) throws Exception {
                    orderListener.onPayResult(payResult);
                }

            });
}

支付结果返回处理

返回例子:
resultStatus={9000};memo={};result={{"alipay_trade_app_pay_response":{"code":"10000","msg":"Success","app_id":"2016091300503896","auth_app_id":"2016091300503896","charset":"utf-8","timestamp":"2018-08-28 17:51:11","out_trade_no":"nVElbd74TW6WnEyxQwvX8A","total_amount":"0.01","trade_no":"2018082821001004680500208879","seller_id":"2088102175487650"},"sign":"W0Hg9k4GxL8Oaxymvqk2i65WNDQxYp6HGve32ek6VjSRnymmI3GQTjpQVbZuDzvjcwQ/HIkM97PoBGAVlTmi/wiJcqDgSSDzDY7AFnNN0OcK0ehWGwKQINA4IDGh51A7yY/vYKmR0VW+2OwGhlRPPMMZtQOEqh8a9/aIijzT6ZLwy9Hl4ayG/fVKhdC1VdckF6+C25BFNp3fIxarg5tfEunm7N9iWngKCUsnP+IZz05OHdvynimgYPcBnbBERHG97GVqRT/EdBWTQyIDMc0LemScAYxJixTVgXDkRddQjzWZ7HgLdBfjs0nXY24puHudT76ERxVY+8NkoKle/QI+FA==","sign_type":"RSA2"}}
也可以自己打log看看
处理示例代码:

          //支付宝支付
            PayUtils.aliPay(this, result.getSignDataStr(), new PayUtils.OrderListener() {
                @Override
                public void onPayResult(String payResult) {
                    PayResult pr = new PayResult(payResult);
                    String rs = pr.getResultStatus();
                    String r = pr.getResult();
                    switch (rs) {
                        case AliPayResultStatus.PAY_SUCCESS:
                            ToastUtils.show(R.string.pay_success);
                            //通知接口支付成功
                           
                            break;
                        case AliPayResultStatus.PAY_PROCESSING:
                        case AliPayResultStatus.PAY_UNKNOWN:
                            ToastUtils.show(R.string.pay_fail);
                            //支付可能成功,要接口去查询

                            break;
                        default:
                            ToastUtils.show(R.string.pay_fail);
                            //通知接口支付失败,取消订单
                            
                    }
                    
                }
            });

上面方法中:

  1. //通知接口支付成功 //支付可能成功,要接口去查询 //通知接口支付失败,取消订单。根据你产品需求要不要通知你服务器做的操作。正常是要的,用来改变订单状态
  2. PayResult.class
public class PayResult {
private String resultStatus;
private String result;
private String memo;

public PayResult(String rawResult) {

    if (TextUtils.isEmpty(rawResult))
        return;

    String[] resultParams = rawResult.split(";");
    for (String resultParam : resultParams) {
        if (resultParam.startsWith("resultStatus")) {
            resultStatus = gatValue(resultParam, "resultStatus");
        }
        if (resultParam.startsWith("result")) {
            result = gatValue(resultParam, "result");

        }
        if (resultParam.startsWith("memo")) {
            memo = gatValue(resultParam, "memo");
        }
    }
}

@Override
public String toString() {
    return "resultStatus={" + resultStatus + "};memo={" + memo
            + "};result={" + result + "}";
}

private String gatValue(String content, String key) {
    String prefix = key + "={";
    return content.substring(content.indexOf(prefix) + prefix.length(),
            content.lastIndexOf("}"));
}

public String outOrder() {
    String order = ""out_trade_no"";

    if (result.contains(order)) {
        String begin = result.substring(result.indexOf(order));
        String ss = begin.split(",")[0];
        String newS = ss.replace(""", "")
                .replace("}", "")
                .replace(":", "")
                .replace("out_trade_no", "");
        try {
            return newS;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return "";
}

/**
 * @return the resultStatus
 */
public String getResultStatus() {
    return resultStatus;
}

/**
 * @return the memo
 */
public String getMemo() {
    return memo;
}

/**
 * @return the result
 */
public String getResult() {
    return result;
}}

最后给下支付返回码表

AliPayResultStatus.class

public class AliPayResultStatus {

/**
 * 订单支付成功,唯一肯定是支付成功的
 */
public static final String PAY_SUCCESS = "9000";
/**
 * 正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
 */
public static final String PAY_PROCESSING = "8000";
/**
 * 订单支付失败
 */
public static final String PAY_FAIL = "4000";
/**
 * 重复请求
 */
public static final String PAY_REPEAT = "5000";
/**
 * 用户中途取消
 */
public static final String PAY_PROCESS_CANCEL = "6001";
/**
 * 网络连接出错
 */
public static final String PAY_NET_ERROR = "6002";
/**
 * 支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
 */
public static final String PAY_UNKNOWN = "6004";}

还有一个直接弃用沙箱调试模式,否则提示支付失败也有可能不知道错在那,怕金额大,和接口商量,测试服务器就用0.01测试。
如接入过程中有问题可私信我

作者 oshook
安卓技术 6 月 21,2023

RxJava1升级为RxJava2

升级的原因:app在后台运行过久或者一会,重新打开时,有几率闪退。

抓到的log:
java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add onError handling.
Caused by: rx.exceptions.MissingBackpressureException

java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add `onError` handling.
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:57)
    at android.os.Handler.handleCallback(Handler.java:891)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:207)
    at android.app.ActivityThread.main(ActivityThread.java:7470)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:958)
 Caused by: rx.exceptions.OnErrorNotImplementedException
    at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:386)
    at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:383)
    at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44)
    at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:153)
    at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115)
    at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.checkTerminated(OperatorObserveOn.java:273)
    at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:216)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
    at android.os.Handler.handleCallback(Handler.java:891) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:207) 
    at android.app.ActivityThread.main(ActivityThread.java:7470) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:958) 
 Caused by: rx.exceptions.MissingBackpressureException
    at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.onNext(OperatorObserveOn.java:160)
    at rx.internal.operators.OperatorSubscribeOn$1$1.onNext(OperatorSubscribeOn.java:53)
    at rx.internal.operators.OnSubscribeTimerPeriodically$1.call(OnSubscribeTimerPeriodically.java:52)
    at rx.Scheduler$Worker$1.call(Scheduler.java:137)
    at rx.internal.schedulers.EventLoopsScheduler$EventLoopWorker$2.call(EventLoopsScheduler.java:189)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:784)

百度出来的解释是产生事件太快,且太多,处理事件的速度太慢。就好像家里面米太多,吃不完,放太久坏掉了。

RxJava1没有处理这种情况,也可以百度搜背压处理。如果能解决就不用更新了。我项目不行,只好大改。
听说RxJava2有对这种情况处理

换就完事了

升级步骤如下

步骤:1、

api 'com.trello:rxlifecycle-components:1.0'
api 'com.trello:rxlifecycle:1.0' 

改为

api 'com.trello.rxlifecycle2:rxlifecycle:2.2.1'
api 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.1'
api 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.1'

2、subscribe不再支持单个Subscriber了,
现支持需要3个参数

subscribe(Consumer super T> onNext, Consumer super Throwable> onError,
Action onComplete)
或者subscribe(Observer super T> observer)

项目中改动位置示例
.subscribe(new ProgressSubscriberNext(basePar, listenerSoftReference, views),new ProgressSubscriberError(listenerSoftReference, views),new ProgressSubscriberCompleted(listenerSoftReference, views));
3、不支持Subscription来解除订阅了,用Disposable来代替了
项目中改动位置示例

fun dealCountDownS(second:Int,disposableObserver: Consumer): Disposable {
return Observable.interval(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.take(second as Long)
.subscribe(disposableObserver)
}

有问题请留言

作者 oshook
安卓技术 6 月 21,2023

git创建分支

步骤1:创建远程分支

进入已经是git的项目,当前是master主分支上

打开git bash
1、 创建分支
git branch your_branch

2、切换到创建的分支
git checkout your_branch

3、add和commit,准备提交分支
git add .
git commit -m “新建分支”

4、提交分支到远程仓库
git push origin your_branch

步骤2:正常自己打开项目就能看到创建的分支。

这里介绍同事要获取分支

很简单,同事在master主分支获取下代码就好。这样远程分支就获取下来了,但是本地还是没有该分支的。打开Android studio,在远程分支上check as
示例图:

branch.png

步骤3:这是可以随意切换分支了,不过有点要注意,修改过的内容记得add,commit。不然切换其他分支时也会前面分支修改过的内容

因为未add的内容不属于任何一个分支, 未commit的内容也不属于任何一个分支。 也就是说,对于所有分支而言, 工作区和暂存区是公共的

步骤4:主分支合并分支代码

vcs–>git–>merge changes

这就是创建分支的全部内容了,剩下的都是基本操作
其他命令可参考:http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html
咋就没人给个赞赏呢

作者 oshook
安卓技术 6 月 21,2023

kotlin基本数据类型

数组

一维数组 lateinit var b:IntArray
二维数组 lateinit var a:Array

更方便的做法:

var int_array:Array = arrayOf(1, 2, 3)
var a:Array> = arrayOf(arrayOf("北京"), arrayOf("上海"))

字符串

split方法返回的是List
var strList:List = origin.split(".")

通过下标访问字符串指定位置的字符

origin.get(number).toString()

输出转义字符
如下输出的$

"${'$'}$origin"

容器

java没法在声明时并初始值,但kotlin可以
Set
mutableSet 可以添加元素,但不能指定添加到那个位置,删除也是一样。不可以修改元素,但可以添加相同的元素进行替换

Map
MutableMap
put方法如果已经有值,则替换,没有,则新增
初始化有to,Pair两种方式

var goodsMap: Map = mapOf(" 苹果 " to "iPhone8")
var goodsMutMap: MutableMap = mutableMapOf(Pair(" 苹果", "iPhone8")

forEach遍历

var desc = ""  
goodsMutSet.forEach { desc = "${desc}ݷᑍғ ${it}n" }
作者 oshook
安卓技术 6 月 21,2023

OnErrorNotImplementedException

Exception thrown on Scheduler.Worker thread. Add onError handling

用Observable是不是没有重写onError方法处理异常,可以全局搜

示例代码:

Observable.timer(defaultCountDownTime, TimeUnit.MILLISECONDS)
            .compose(this.bindToLifecycle())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1() {
                @Override
                public void call(Long aLong) {
                    

                }
            });

上面代码就是没有重写onError,出错时就闪退了

作者 oshook
安卓技术 6 月 21,2023

防止界面重建

在清单文件相应的activity配置,重点是configChanges
android:screenOrientation=”portrait”
android:configChanges=”orientation|keyboardHidden|keyboard|screenSize”

作者 oshook
安卓技术 6 月 21,2023

点赞防刷新整个列表,闪一下跳动的问题

闪一下原因:
notifyDataSetChanged();用它来刷新列表,如果列表本来就有点卡,再用它来刷,闪跳动的效果更明显
解决方案:
用notifyItemChanged来刷新item内容

示例代码:

for (int i = 0; i  0) {
                notifyItemChanged(i + getHeaderLayoutCount(), "点赞成功");
            } else {
                notifyItemChanged(i, "点赞成功");
            }
            break;
        }
    }
作者 oshook
安卓技术 6 月 21,2023

Adapter滑动卡顿优化

1、点击事件过多的用new OnClickListener{}直接匿名内部类

原因:在滑动的过程中会不断的重复创建新的OnClickListener,旧的不断的被回收当需要回收的对象过多的时候会引起GC,导致列表卡顿。
解决方案
可以建一个通用的OnClickListener,不会建的,就在类上集成点击接口,把数据放入Button的Tag中,根据id来判断是哪个Button执行了点击,来取出数据、执行不同的逻辑
多个参数怎么办,那就setTag多个
示例代码

helper.getView(R.id.cl_mood_item).setTag(R.id.adapter_item_id,item.getId());
    helper.getView(R.id.cl_mood_item).setTag(R.id.adapter_position,helper.getAdapterPosition());
    helper.getView(R.id.cl_mood_item).setOnClickListener(this);

@Override
public void onClick(View view) {
    switch (view.getId()){
        
        case R.id.cl_mood_item:
            if(view.getTag(R.id.adapter_item_id) != null && view.getTag(R.id.adapter_item_id) instanceof Integer &&
                    view.getTag(R.id.adapter_position) != null && view.getTag(R.id.adapter_position) instanceof Integer){
                //todo your
            }
            break;
        

    }
}

敬请后续。。。

作者 oshook
安卓技术 6 月 21,2023

BaseQuickAdapter混淆文件

-keep class com.chad.library.adapter.** {
*;
}
-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
-keep public class * extends com.chad.library.adapter.base.BaseViewHolder
-keep public class * extends com.chad.library.adapter.base.entity.MultiItemEntity
-keepclassmembers  class **$** extends com.chad.library.adapter.base.BaseViewHolder {
 (...);
}
作者 oshook

上一 1 … 3 4 5 … 7 下一个

Copyright © 2023 | 粤ICP备14006518号-3