微包接入说明

集成说明

添加 .aar

请将 XXXXX.aar 放入 app/libs目录中

android{
   compileSdkVersion 33
   defaultConfig {
      // 运行版本需要 21 <= target <= 33
      targetSdkVersion 33
   }

    repositories {
        flatDir { dirs 'libs' }
    }


   packagingOptions {
      // 防止aar内部的.so 被压缩导致异常
      doNotStrip "**/*.so"
   }
}

dependencies {
    // 专业版
    implementation(name: "wbx_professional_sdk_1.x.x", ext: "aar")
    // 集成版
    implementation(name: "wbx_community_sdk_1.x.x", ext: "aar")
    // 备注:专业版与集成版二选一
}

备注:如果导入了 aar,但是在代码中却没有相关package,请 clean project,并且rebuild project,如果还是未找到,请 clean project 后删除根目录的 .idea 与 .gradle 文件夹,关闭Android Studio然后重新打开项目

一般来说clean并且rebuild后就可以找到相关package了

添加移动端商编证书(XXXXXXXX.cer)

微包移动端SDK版本选用1.5.0或更新的版本,将不用执行此步骤.微包移动端SDK内部将自动会获取该商户证书.

注意:在22年7月(含7月)之前开通微包的商户不能使用‘自动获取商户证书功能’

将移动端商编证书(XXXXXXXX.cer)拷贝到assets目录下,证书可配置在assets的子目录中,具体配置方式请看 对外提供的方法 (WalletPay) 章节

添加静态活体(即:刷脸认证)

静态活体功能需要联系我司商务经理进行申请授权文件。 申请授权文件中的包名应该与要集成的App保持一致

获取到拿到License文件后(即:xxx.lic)

<application>
   <meta-data
           android:name="com.ehking:android-sensetime:lic"
           android:value="0d5e791c-1577-45e7-ade5-b29795b9aa95.lic" />
</application>

当然你也可以通过 AndroidManifest 指定你的.lic名称

<meta-data
    android:name="com.ehking:android-sensetime:lic"
    android:value="YOU_CUSTOM_LICENCE_NAME.lic" />

Tip1: Demo中没有活体认证文件,需要联系我司商务进行申请授权文件。
Tip2: 如果想在Demo试用申请授权文件,需要商户手动修改Demo应用的包名(包名与授权文件申请的包名必须一致)。

添加依赖

android{
   compileOptions {
      sourceCompatibility JavaVersion.VERSION_11
      targetCompatibility JavaVersion.VERSION_11
   }
}

dependencies {
    implementation 'com.android.support:appcompat-v7:28+'
    implementation 'com.android.support:design:28+'

    implementation 'com.google.code.gson:gson:latest.integration'
    implementation 'com.alibaba.pdns:alidns-android-sdk:latest.integration'
    implementation 'dnsjava:dnsjava:latest.integration'
    implementation 'org.slf4j:slf4j-api:latest.integration'
}

如果你的主体项目是 AndroidX,请看下面:

请在 gradle.properties 中添加以下内容

Android官方文档请看这里

android.useAndroidX=true
android.enableJetifier=true

SDK 中使用到的权限

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="29"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.INTERNET" />

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />

    <!-- 读取手机号码与接收短信权限为敏感权限,如需要请自行添加  -->
    <!-- 此功能为适配部分手机使用短信支付时不能自动填充短信的问题  -->
    <!-- 具体请查看 '对外提供的方法 (WalletPay)' 章节-->
    <!-- <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />-->
    <!-- <uses-permission android:name="android.permission.RECEIVE_SMS" />-->

混淆例外

-dontwarn com.ehking.**
-keep class com.ehking.**{*;}

-dontwarn net.bean.**
-keep class net.bean.**{*;}

-dontwarn com.livedetect.**
-keep class com.livedetect.**{*;}

-dontwarn ccom.sensetime.**
-keep class com.sensetime.**{*;}

-dontwarn com.hisign.**
-keep class com.hisign.**{*;}

-keep class com.alibaba.pdns.** {*;}

-dontwarn org.xbill.DNS.**
-keep class org.xbill.DNS.**{*;}

-dontwarn org.slf4j.**
-keep class org.slf4j.**{*;}

//若选用集成版还需要加入此例外
-dontwarn com.payeasenet.**
-keep class com.payeasenet.sdk.**{*;}

基本使用

// 商户商编ID
String merchantId = "89XXXXX95";
// 用户钱包ID
String walletId = "XXXXXXXXXXXXXXXXXX";
// 业务类型。{@code AuthType.RECHARGE}充值业务
AuthType authType = AuthType.RECHARGE;
// 注册业务执行回调
OnEvokeResultListenerAdapter listener = new OnEvokeResultListenerAdapter(){

    // 所有的回调都会先触发此方法
    @override
    public void onEvokeResult(AuthType type, Status status, String cause){
        /*_*/
    }

    // 可选方法:充值业务回调
    @override
    public void onRechargeResult(Status status, String cause){
        // 注销业务执行回调
        WalletPay.removeOnEvokeResultListenerList(this);
    }

    /*其它各业务可选回调*/
};
// 关于Token 请看 '唤起业务' 章节
String token = "XXXX"
WalletPay.evoke(merchantId, walletId, token, authType, listener);

自定义Activity Style

    <!-- 可覆写此样式 -->
    <style name="CustomWbxSdkTheme" parent="WbxSdkTheme.Base">

    </style>

唤起业务

基本所有业务都需要使用到token

token 是服务端生成的动态码,需要请求后台进行获取。

专业版中token的获取并非由SDK供应商直接提供,而是需要商户服务端进行开发相应接口(即:预下单接口,具体可看微包服务端接入文档),商户的移动端从商户服务端接口获取到返回的token再传入WalletPayevoke方法中

Map<String, Object> map = new HashMap<>();
map.put(/*...*/)
// ...
netApiService.fetchWalletRecharge(map, it -> {
    WalletPay.evoke(
    // 商户商编ID
    "89XXXXX95",
    // YOU_WALLET_ID
    "6288..略..752",
    // 从商户服务端获取 Token
    it.getToken(),
    // 业务类型
    AuthType.RECHARGE,
    // 回调监听适配器
    new OnEvokeResultListenerAdapter(){
        // ...
    }
});

提供的业务(AuthType)

enum AuthType  {
    VERIFY_CERT("安装数字证书"),
    FIRSTSET_PASSWORD("设置支付密码"),
    ACCESS_SAFETY("安全设置"),
    ACCESS_SAFETY_OPEN_FACE("开启人脸识别"),
    ACCESS_CARDlIST("绑卡管理"),
    VALIDATE_PASSWORD("确认密码"),
    SILENCE_RESCIND("解除沉默账户"),
    INSTALL_CERT("Token可空, 直接启动安装证书页面"),
    MANUAL_CHECK_CER("手动下载证书"),
    AUTO_CHECK_CER("自动下载证书"),
    AUTH_PERSON("人像认证"),
    // 以下为收银台业务
    RECHARGE("充值"),
    TRANSFER("转账"),
    WITHHOLDING("提现"),
    REDPACKET("发红包"),
    APP_PAY("微包支付和服务号订单支付"),
    WEB_PAY("WEB支付"),
}

对外提供的方法 (WalletPay)

/**
 * 获取附加结果数据
 * 目前仅用在扫码付功能中,提供查询订单能力, 具体返回内容可查看Demo中扫码付相关代码
 */
public static Object getResultObject();

/**
 * 设置证书目录
 * 也可以通过<meta-data>标签的方式进行注册
 * 关于使用优先级:
 *  1. setCertificateDirectory
 *  2. <meta-data>
 * 注意:若不设置路径,则会从 assets的根目录查找证书
 * <pre>
 *     <meta-data
 *         android:name="com.ehking:android-webox:cert-dir"
 *         android:value="YOUR CER DIR"
 *     />
 * </pre>
 *
 * @param dir 示例:e/g/a/cer,
 *
 * 关于商编证书的特别注意事项:
 * 商户会持有两个 'XXXXX.cer'的证书(即:公钥与私钥),分别用在移动端与服务端。
 * 如果使用错误,会出现业务启动失败(即:证书解密失败问题)
 */
public static void setCertificateDirectory(String dir);

/**
 *  是否禁用敏感权限;
 *  禁用敏感权限,ture禁用/false不禁用;
 *  禁用后, 收银台短信码支付方式, 不会自动获取短信验证码
 *  默认为true;若改为false后需要在AndroidManifest.xml中添加以下权限
 *  <pre>
 *      <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
 *      <uses-permission android:name="android.permission.RECEIVE_SMS" />
 *  </pre>
 */
public static void setDisableSensitivePermissions(boolean disable)

/**
 * 获取当前密码验证页面的验证方式
 * @return PayAuthType
 */
public static PayAuthType getCurrentDefaultValidatePasswordType();

/**
 * 设置密码验证页面的验证方式(非支付收银台支付校验方式)
 * 默认为支付密码确认{@link PayAuthType.PAY_PASSWORD}
 */
public static void setDefaultPayModeOfVerifyPwd(PayAuthType type);

/**
 * 添加唤起业务结果监听
 */
public static void addOnEvokeResultListener(OnEvokeResultListener listener);


/**
 * 删除唤起业务结果监听
 * 业务结束务必注销监听,否则某些业务可能会通知多次
 */
public static void removeOnEvokeResultListener(OnEvokeResultListener listener);

/**
 * 屏幕适配例外名单
 * 如果你使用的是 AndroidAutoSize 框架,
 * 需要将例外名单进行添加
 * 防止页面出现适配问题
 * {@link https://github.com/JessYanCoding/AndroidAutoSize}
 */
public static List<Class<?>> notRequiredScreenAdaptList();

/**
 * @param  merchantId  商户商编.
 * @param  walletId  钱包Id.
 * @param  token   调起业务需要的token.
 * @param  source  调起业务的code.
 * @param  onEvokeResultListener  注册唤起业务结果监听
 * @param  requestId 唯一标识,后台查询业务使用, 一般时间戳作为入参
 *                  {@code System#currentTimeMillis()}
 */
public static void evoke(
    String merchantId,
    String walletId,
    String token,
    AuthType source,
    OnEvokeResultListener listener,
    String requestId
);

/**
 * 清除钱包缓存
 * 使用这个函数请慎重,除非你能保证业务未执行或已经结束在使用它,
 * 因为,如果在业务唤起阶段中使用,业务将会被中断或出现异常
 */
public static void clearWalletCache();

/**
 * 获取当前SDK版本号
 */
public static String getSdkVersion();

/**
 * 设置Debug模式
 * @param debug true开启Debug模式/false关闭Debug模式
 * 如果开启Debug模式则会多出相应的Toast提示以及堆栈日志
 */
public static void setDebug(Boolean isDebug);

/**
 * 设置随机数字键盘
 * @param random true开启随机数字键盘/false关闭随机数字键盘
 */
public static void setRandomKeyboard(Boolean random);

/**
 * 删除证书
 * 备注:指开户后从服务端下载或手动安装存储在存储器中的证书,
 *      非商编证书(XXXXXX.cer)
 * @param walletId 要删除的钱包ID
 * @return Map<String, Object>
 * <pre>
 * {
 *   "delResult" : Boolean, // 是否删除成功
 *   "cerFile" : String, // 证书路径
 *   "existCer" : Boolean, // 证书是否存在
 * }
 * </pre>
 */
public static Map<String, Object> deleteCert(String walletId);

/**
 * 设置装饰布局(仅支持按钮与Toolbar)
 * 布局类型由 com.ehking.sdk.wepay.platform.decoration.WidgetCate 提供
 * 可以设置渐变色背景 接收类型 Drawable
 * 可以设置文字颜色 接收类型 ColorStateList
 * 若空则由SDK提供默认的背景与文字颜色
 */
public static void setWidgetDecoration(List<WidgetDecoration> list);

/**
 * 设置toolbar返回键样式
 * @param ToolBarBackColorStyle
 * <pre>
 * enum ToolBarBackColorStyle{
 *    AUTO, // 自动设置, BLACK/WHITE
 *    BLACK, // 黑色样式
 *    WHITE, // 白色样式
 * }
 * </pre>
 */
public static void setToolBarBackImg(ToolBarBackColorStyle style);

/**
 * 私钥证书是否存在
 * 备注:指开户后从服务端下载或手动安装存储在存储器中的证书,
 *      非商编证书(XXXXXX.cer)
 * @param walletId 如果空则查询当前钱包ID的私钥证书,
 *                 如果有值则查询指定钱包ID是否有证书
 * @return Boolean 证书存在 true, 反之 false
 */
public static Boolean existsPrivateKeyCerFile(String walletId);

/**
 * 获取设备号码(即:android.provider.Settings.Secure.ANDROID_ID)
 */
public static String getDeviceNumber();

/**
 * 可以调用此方法关闭 Loading 弹窗
 */
public static void dismissLoading(Activity activity);

/**
 * 自定义Loading
 *
 * 只接收带有 Context 型参的构造函数
 * <pre>
 *   public LoadingDialog(Context context) {
 *      super(context, R.style.your_custom_loading_dialog);
 *   }
 * </pre>
 *
 * NOTE:不要将构造函数混淆,否则无法反射到此函数签名
 * <pre>
 * // 这里展示的是Demo中自定义Loading剔除混淆
 * -keep class com.payeasenet.webox.platform.widget.loading.LoadingDialog{public *;}
 * </pre>
 */
public static void setCustomLoading(Class<? extends AlertDialog> clz);

/**
 * 自定义权限申请提示内容
 */
public static void setCustomPermission(CustomPermission customPermission)

密码验证枚举说明 (密码验证页面使用)

enum PayAuthType{
    PAY_PASSWORD("默认密码"),
    FORCE_PAY_PASSWORD("强制密码"),
    FACE_SCAN("刷脸"),
    FORCE_FACE_SCAN("强制刷脸"),
    FINGERPRINT("指纹"),
    UNKNOWN("")
}

AuthType.VALIDATE_PASSWORD业务适用

备注:商户使用WalletPayevoke方法调用收银台业不能指定为包支付具体验密方式。微包的收银台业务验密由微包服务端指定。

关于业务回调 (OnEvokeResultListener)

// 回调接口
public interface OnEvokeResultListener

// 为了方便,微包提供了适配类
public class OnEvokeResultListenerAdapter implements OnEvokeResultListener

回调内容

/**
 * 所有业务的回调都会触发此方法
 * @param source 业务类型
 * @param status 回调状态
 * @param cause 原因
 * 备注:成功类型也可能会带有原因
 * Status的父类
 * 具体说明请看 '关于业务回调状态类型' 章节
 */
void onEvokeResult(AuthType source, IStatus status, String cause);

// 校验数字证书校验
void onVerifyCertResult(Status status, String cause)

// 首次设置支付密码
void onFirstPasswordResult(Status status, String cause)

// 唤起安全设置页面
void onAccessSafetyResult(/*型参与上相同*/)

// 唤起安全设置开启人脸
void onAccessSafetyOpenFaceResult(/*型参与上相同*/)

// 唤起卡列表页面
void onAccessCardListResult(/*型参与上相同*/)

// 确认密码
void onValidatePasswordResult(/*型参与上相同*/)

// 手动下载证书
void onManualCheckCerResult(/*型参与上相同*/)

// 自动下载证书
void onAutoCheckCerResult(/*型参与上相同*/)

// 人像认证
void onAuthPersonResult(/*型参与上相同*/)

// 发起充值
void onRechargeResult(/*型参与上相同*/)

// 发起转账
void onTransferResult(/*型参与上相同*/)

// 发起提现
void onWithholdingResult(/*型参与上相同*/)

// 发起发红包
void onRedPacketResult(/*型参与上相同*/)

// 微包支付和服务号支付
void onAppPayResult(/*型参与上相同*/)

// Web支付
void onWebPayResult(/*型参与上相同*/)

// 解除沉默账户
void onSilenceRescindResult(Status status, String cause);

关于业务回调状态类型 (Status)

普通业务与收银台业务的回调状态枚举

enum Status{
    SEND("发起成功"),
    PROCESS("处理中"),
    SUCCESS("成功"),
    FAIL("发起失败/失败"),
    CANCEL("取消"),
    UNKNOWN(""),
}

需要注意:

微包收银台业务的回调状态仅表示业务提交结果而非订单状态,若回调结果状态是Status.SUCCESSStatus.SENDStatus.PROCESS仍需要商户自行查询获取该笔订单的实际状态.

其它可配置项

public class DemoApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // 设置是否为Debug模式
        WalletPay.setDebug(BuildConfig.DEBUG);
        // 是否禁用敏感权限
        WalletPay.setDisableSensitivePermissions(true);

        // 默认最少为10秒,少于10秒设置无效
        WbxSdkConstants.Http.setTimeoutSeconds(30);

        // 设置按系统返回键时关闭缓冲弹窗上限次数
        WbxSdkConstants.GlobalConfig.setBackPressedLimitCountOnLoadingTip(1);
        // 是否禁用按系统返回键时关闭缓冲弹窗功能
        WbxSdkConstants.GlobalConfig.setDisableBackPressedOnLoadingTip(false);
        // @author:         zhiwei@payeasenet.com 2022/4/26 16:30
        // @description:    默认可不设置,会自动走阿里的域名解析
        // WbxSdkConstants.Http.setDns(new DnsResolver());
        // 可在调试状态开启
        // 抓取崩溃日志存储至外部存储器目录中
        // 存储位置:
        // android 11+ "/sdcard/Android/data/com.payeasenet.webox/files/Alarms/crash/"
        // low version "/sdcard/wbx/files/Alarms/crash/"
        // CrashHandler.getInstance(this);
    }
}

编译问题与异常的解决说明

SDK内部异常抓取

public class DemoApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        if(BuildConfig.DEBUG){
            CrashHandler.getInstance(this);
        }
    }
}

编译问题

依赖冲突

android{
   // 配置全局依赖剔除
   configurations {
      // 包名仅示例效果,请根据自身情况填写
      compile.exclude group: 'org.slf4j', module: 'slf4j-api'
   }

   // 配置全局库强制引用
   configurations.all {
      resolutionStrategy {
         force 'org.slf4j:slf4j-android:1.7.21'
      }
   }
}

// 非全局配置,仅针对某个引用依赖
dependencies {
   implementation(name: "wbx_professional_sdk_1.x.x", ext: "aar"){
      // 你可以指定剔除某个依赖
      exclude group: 'com.android.support'
      exclude group: 'e.g.a', module: 'xx'
   }
// 或者你可以强制指定以当前版本为准
   implementation('com.android.support:support-v4:27') {
      // 这个方法在高Gradle版本中已经失效,强制指定只能使用全局方式
      force = true
   }
}

更多解决依赖冲突的方式请自行网上查找资料

导入aar不生效

如果导入了 aar,但是在代码中却没有相关package,请 clean project,并且rebuild project,如果还是未找到,请 clean project 后删除根目录的 .idea 与 .gradle 文件夹,关闭Android Studio然后重新打开项目

一般来说clean并且rebuild后就可以找到相关package了

演示项目,AS编译报错

  1. Project中gradle版本是否已经下载到本地
  2. local.properties 中Android SDK路径是否正确

依赖下载慢(可选国内镜像)

请根据自己的需求选择相关镜像库

maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }

常见异常

版本更新说明

1.5.3

1.5.2

1.5.1

1.5.0

1.4.1

1.4.0

1.3.3

1.3.2

1.3.1

1.3.0

1.2.0

1.1.10

1.1.9

1.1.8

1.1.7

1.1.6

1.1.5

1.1.4

1.1.3

1.1.2

1.1.1

1.1.0

1.0.7.1

1.0.7

1.0.6

1.0.5

1.0.4

1.0.3

1.0.2

1.0.1

1.0.0