Android微信支付宝QQ支付接入详解-Unity3D原生支付交互接入PayUnityUtils

一、微信支付
第一步登录微信开放平台:https://open.weixin.qq.com/,进入账号中心进行开发者资质认证,需要填写公司资料,包括但不限于,公司注册号,公司营业执照,公司对外办公电话,公司 对公银行卡信息(卡号,发卡行)。审核时间为
一周左右,进行开发者资质认证需要支付 300 元人民币/年,只有具备开发者资质认证的开发者才能够使用 app 支付,授权登录等接口。
申请 APP_ID/APP_KEY
每个应用/游戏要调用微信的接口都需要有一个微信标志,这个唯一标志通常成为 APP_ID 或者 APP_KEY,各开放平台差异不大进入管理中心,创建移动应用,每个开发者具有 10 个应用的创建机会,好在创建的应用可以随时删除。 已上线的应用就不建议手贱删除!!申请 appid 需要填写应用信息:应用名称,包名,签名(keystore 的 md5 值去分号小写),icon(2828 & 108108),app 下载地址等信息,即可分配到一个 appid。

开通微信商户平台,登录微信商户平台https://pay.weixin.qq.com,这里也是需要300元人民币/年开通微信支付功能,绑定企业银行,开通企业微信商户,在产品中心中,开通“APP支付”功能

微信截图_20190518163505.png

开通成功之后绑定微信开放平台的APPID
微信截图_20190518163723.png

在产品中心中,左边列表选择“APPID授权管理”进行绑定,


微信截图_20190518163835.png

微信截图_20190518163850.png

此时,微信支付申请就搞定了,可以进行开发了
Android studio 新建工程
在build.gradle 中的dependencies 中
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
依赖微信支付,登录的依赖包

在工程的目录包名下新建目录wxapi,新建WXPayEntryActivity.java类,此类名称不可以变,必须放在wxapi下,如包名为com.xx.xxx.xxx,WXPayEntryActivity类就放在com.xx.xxx.xxx.wxapi下,
在AndroidManifest.xml中配置
<activity
android:name="工程包名.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"/>
及网络权限
<uses-permission android:name="android.permission.INTERNET" />

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if(WeiXinPay.getInstance(this)!=null){
        WeiXinPay.getInstance(this).getWXApi().handleIntent(getIntent(), this);
    }else {
        finish();
    }
}
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
    if (!WeiXinPay.getInstance(this).getWXApi().handleIntent(intent, this)) {
        finish();
    }
}
@Override
public void onReq(BaseReq baseReq) {

}

@Override
public void onResp(BaseResp baseResp) {
    //4、支付结果回调 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5

    Log.e("WXPayEntryActivity", "baseResp=" + baseResp.toString());
    if(baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
        Log.e("WXPayEntryActivity", "errStr=" + baseResp.errStr);
        if(WeiXinPay.getInstance(this) != null) {
            if(baseResp.errStr != null) {
                Log.e("WXPayEntryActivity", "errStr=" + baseResp.errStr);
            }
            WeiXinPay.getInstance(this).onResp(baseResp);
            finish();
        }
    }
}

}
回调中 errCode 值列表:
0 支付成功
-1 发生错误 可能的原因:签名错误、未注册 APPID、项目设
置 APPID 不正确、注册的 APPID 与设置的不匹配、其他异常
等。
-2 用户取消 发生场景:用户不支付了,点击取消,返回 APP。

微信支付的回调再该类的onResp方法中回调
微信支付类,通过服务器返回的数据,拿到appid,注册到微信 mIWXAPI.registerApp(appId);
其中服务端返回的数据中partnerid 就是商户id
根据服务端返回的数据拉起支付
PayReq req = new PayReq();
req.appId = payBean.getAppid();
req.partnerId = payBean.getMch_id();
req.prepayId = payBean.getPrepay_id();
req.nonceStr = payBean.getNonce_str();
req.timeStamp = payBean.getTimestamp();
req.packageValue = "Sign=WXPay";
req.sign = payBean.getSignB();//服务端的签名 正式使用
//req.sign = genAppSign(payBean).toUpperCase();//客户端的签名 测试
mIWXAPI.sendReq(req);

需要注意的是,在微信开放平台创建的应用,填写的包名和签名,必须和工程保持一致,否则拉起支付有可能返回-1,

package 是不变的,sign 是服务签名的,客户端测试的话,可以放在客户端签名
测试代码
orderWechat = "{\n" +
" "appid": "wxca3042x2xxxxx4e344cf01",\n" +
" "partnerid": "1526501",\n" +
" "prepayid": "wx161841xxxxxxx542151",\n" +
" "timestamp": "1558xxx003316",\n" +
" "noncestr": "c8J2CxxnDxx7qDx15dus",\n" +
" "package": "Sign=WXPay",\n" +
" "sign": "34CBBAxxxxxxx0F59775F"\n" +
"}";
if(TextUtils.isEmpty(orderWechat)){
Toast.makeText(MainActivity.this,"预付订单为空",Toast.LENGTH_SHORT).show();
return;
}
//微信支付
// * 注意
// * 微信的APPID 和签名信息及报名和微信开放平台填写的要一致
pay.payDoraVip(MainActivity.this,"PHP",JPay.PayMode.WXPAY,orderWechat);

客户端签名样例,key值按升序拼接在用MD5加密
private String genAppSign(WechatPayBean payBean) {

    List<NameValuePair> signParams = new LinkedList<>();
    signParams.add(new NameValuePair("appid", payBean.getAppid()));
    signParams.add(new NameValuePair("noncestr", payBean.getNonce_str()));
    signParams.add(new NameValuePair("package", "Sign=WXPay"));
    signParams.add(new NameValuePair("partnerid",payBean.getMch_id()));
    signParams.add(new NameValuePair("prepayid", payBean.getPrepay_id()));
    signParams.add(new NameValuePair("timestamp", payBean.getTimestamp()));

    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < signParams.size(); i++) {
        sb.append(signParams.get(i).getName());
        sb.append('=');
        sb.append(signParams.get(i).getValue());
        sb.append('&');
    }
    sb.append("key=");
    sb.append("api密钥");
    String appSign = MD5Utils.getMessageDigest(sb.toString().getBytes());
    return appSign;
}

二、支付宝支付
登录支付宝网站https://auth.alipay.com
进行企业验证,验证完成进入我的开放平台

我的开放平台---开发中心--网页移动应用
立即创建应用,创建完成添加APP支付功能
在工程到导入alipaySdk-20180601.jar包,

/**

  • Created by camming on 2019/11/21.
  • 支付宝支付
    */
private static Alipay mAliPay;
private Activity mContext;
private JPay.JPayListener mJPayListener;

//支付失败
public static final int PAY_ERROR = 0x001;
//支付网络连接出错
public static final int PAY_NETWORK_ERROR = 0x002;
//支付结果解析错误
public static final int RESULT_ERROR = 0x003;
//正在处理中
public static final int PAY_DEALING = 0x004;
//其它支付错误
public static final int PAY_OTHER_ERROR = 0x006;
//支付参数异常
public static final int PAY_PARAMETERS_ERROE = 0x007;


private Alipay(Activity context) {
    mContext = context;
}

public static Alipay getInstance(Activity context){
    if (mAliPay == null) {
        synchronized(WeiXinPay.class){
            if (mAliPay == null) {
                mAliPay = new Alipay(context);
            }
        }
    }
    return mAliPay;
}


public void startAliPay(final String orderInfo,JPay.JPayListener listener){
   boolean bool =  checkAliPayInstalled(mContext);
   if(!bool){
       Toast.makeText(mContext,"支付宝未安装!",Toast.LENGTH_SHORT).show();
       return;

   }
    mJPayListener = listener;
    Runnable payRunnable = new Runnable() {
        @Override
        public void run() {
            PayTask alipay = new PayTask(mContext);
            Map<String, String> result = alipay.payV2(orderInfo, true);
            Message msg = new Message();
            msg.obj = result;
            mHandler.sendMessage(msg);
        }
    };
    Thread payThread = new Thread(payRunnable);
    payThread.start();
}
/**
 * 检测是否安装支付宝
 * @param context
 * @return
 */
public static boolean checkAliPayInstalled(Context context) {

    Uri uri = Uri.parse("alipays://platformapi/startApp");
    Intent intent = new Intent(Intent.ACTION_VIEW, uri);
    ComponentName componentName = intent.resolveActivity(context.getPackageManager());
    return componentName != null;
}


private Handler mHandler = new Handler(Looper.getMainLooper()) {
    @SuppressWarnings("unchecked")
    public void handleMessage(Message msg) {
        PayResult payResult = new PayResult((Map<String, String>) msg.obj);

        Log.e("payResult= ",payResult.toString());
        System.out.print("payResult= "+payResult.toString());

        String resultStatus = payResult.getResultStatus();
        if (mJPayListener ==null){
            return;
        }
        // https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.xN1NnL&treeId=204&articleId=105302&docType=1
        if(payResult == null) {
            mJPayListener.onPayError(RESULT_ERROR,"结果解析错误");
            return;
        }
        if(TextUtils.equals(resultStatus, "9000")) {
            //支付成功
            mJPayListener.onPaySuccess();
        } else if(TextUtils.equals(resultStatus, "8000")) {
            //正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
            mJPayListener.onPayError(PAY_DEALING,"正在处理结果中");
        } else if(TextUtils.equals(resultStatus, "6001")) {
            //支付取消
            mJPayListener.onPayCancel();
        } else if(TextUtils.equals(resultStatus, "6002")) {
            //网络连接出错
            mJPayListener.onPayError(PAY_NETWORK_ERROR,"网络连接出错");
        } else if(TextUtils.equals(resultStatus, "4000")) {
            //支付错误
            mJPayListener.onPayError(PAY_ERROR,"订单支付失败");
        }else {
            mJPayListener.onPayError(PAY_OTHER_ERROR,resultStatus);
        }
    }
};

}

/**

  • create by camming 2019/02/14
  • 情人节也要写代码
  • 支付宝支付
  • */
public AliPayTask(Activity context) {
    this.mContext = context;
}

public AliPayTask(Activity context,String type,JPay.JPayListener listener) {
    this.mContext = context;
    this.mJPayListener =listener;
    this.serverType = type;
}


@Override
protected void onPreExecute() {
    super.onPreExecute();
}


@Override
protected void onPostExecute(String result) {
    Log.e("AideaAliPayTask", "result"+result);
//  AlipayBean resultBean = JSONObject.parseObject(result,new TypeReference<AlipayBean>(){});
    try {
        if (result!=null){
        //  AlipayBean resultBean = JSONObject.parseObject(result,new TypeReference<AlipayBean>(){});
            if(serverType.equals(API_TYPE_PHP)){
                System.out.println("PHP后台返回的数据orderInfo="+result);
                PayUtils.getIntance(mContext).startAliPay(result,mJPayListener);
            }else{
                JSONObject jsonObject=new JSONObject(result);
                int code  = jsonObject.getInt("code");
                if(code==0){
                    String resultData = jsonObject.getString("data");
                    System.out.println("orderInfo="+resultData);
                    ///Toast.makeText(mContext, "正在调起支付", Toast.LENGTH_SHORT).show();
                    PayUtils.getIntance(mContext).startAliPay(resultData,mJPayListener);
                }else{
                    Toast.makeText(mContext, "错误"+jsonObject.getString("message"), Toast.LENGTH_SHORT).show();
                }

            }

        }else {

            System.out.println("get  AliPay exception, is null");
        }
    } catch (Exception e) {
        Log.e("PAY_GET", "异常:"+e.getMessage());
        Toast.makeText(mContext, "异常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
    }
    super.onPostExecute(result);
}

}

三、QQ支付
登录网站https://qpay.qq.com/
申请APP支付,创建应用

image.png

image.png

在工程项目目录下的wxapi目录下,新建一个QQ支付回调的类,我这里是QQCallbackActivity.java
/**

  • Create by camming 2019/02/20
  • qq支付通知
  • */
String appId = "101538445";
IOpenApi openApi;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
   // setContentView(R.layout.activity_callback);

    openApi = OpenApiFactory.getInstance(this, appId);
    openApi.handleIntent(getIntent(), this);
}

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


@Override
public void onOpenResponse(BaseResponse response) {
    String title = "Callback from mqq";
    String message;
    QQPay.getInstance(this).onQQResponse(response);
    if (response == null) {
        message = "response is null.";
        return;
    } else {
        if (response instanceof PayResponse) {
            PayResponse payResponse = (PayResponse) response;

            message = " apiName:" + payResponse.apiName
                    + " serialnumber:" + payResponse.serialNumber
                    + " isSucess:" + payResponse.isSuccess()
                    + " retCode:" + payResponse.retCode
                    + " retMsg:" + payResponse.retMsg;
            if (payResponse.isSuccess()) {
                if (!payResponse.isPayByWeChat()) {
                    message += " transactionId:" + payResponse.transactionId
                            + " payTime:" + payResponse.payTime
                            + " callbackUrl:" + payResponse.callbackUrl
                            + " totalFee:" + payResponse.totalFee
                            + " spData:" + payResponse.spData;
                }
                
            }
        } else {
            message = "response is not PayResponse.";
        }
    }
    
}

}

在AndroidManifest.xml中配置
<activity
android:name="工程包名.wxapi.QQCallbackActivity"
android:launchMode="singleTop"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="qwallet+qq商户id"/>
</intent-filter>
</activity>

导入mqqopenpay.jar,

/**

  • Created by camming on 2019\2\19 0019.
  • code is data data is code
  • qq支付
    */
private static final String TAG = "QQPay";
@SuppressLint("StaticFieldLeak")
private static QQPay mQQPay;
private Context mContext;
private String callbackScheme = "qwallet+qqid";
private IOpenApi openApi;

int paySerial = 1;

public static final String QQ_APP_ID = "qqid";
// 签名步骤建议不要在app上执行,要放在服务器上执行
public static final String APP_KEY = "商户key";

private JPay.JPayListener mJPayListener;

public static QQPay getInstance(Context context){
    if (mQQPay == null) {
        synchronized(QQPay.class){
            if (mQQPay == null) {
                mQQPay = new QQPay(context);
            }
        }
    }
    return mQQPay;
}
private QQPay(Context context) {
    mContext = context;
    if(openApi==null)
        openApi = OpenApiFactory.getInstance(mContext, QQ_APP_ID);
}

/**手机QQ是否已经安装*/
public boolean isMqqInstalled() {
    if(openApi==null)
        return false;
    else
        return openApi.isMobileQQInstalled();
}
/**是否支持手机qq支付*/
public boolean isMqqSupportPay() {
    if(openApi==null)
        return false;
    else
        return openApi.isMobileQQSupportApi(OpenConstants.API_NAME_PAY);
}

// public void startQQPay(String payResult, JPay.JPayListener listener){

// startQQPay(resultBean,listener);
// }
/**
* 开始QQ支付
*
* */
public void startQQPay(String pay, JPay.JPayListener listener){
this.mJPayListener = listener;

    QQPayBean payBean = JSONObject.parseObject(pay,new TypeReference<QQPayBean>(){});
    Log.i("qqpay","payBean="+payBean);

// ToastUtils.show(mContext,payBean);
if(!isMqqInstalled()){
Toast.makeText(mContext,"QQ未安装!",Toast.LENGTH_SHORT).show();
return;
}
if(!isMqqSupportPay()){
Toast.makeText(mContext,"该QQ版本不支持QQ支付!",Toast.LENGTH_SHORT).show();
return;
}
PayApi api = new PayApi();
api.appId = payBean.getAppid();
api.serialNumber = "" + paySerial++;//支付序号
api.callbackScheme = callbackScheme;
api.tokenId = payBean.getPrepay_id();// QQ钱包支付生成的token_id
api.pubAcc = "";
api.pubAccHint = "";
api.nonce = payBean.getNonce_str();
api.timeStamp = System.currentTimeMillis() / 1000;
api.bargainorId = payBean.getMch_id();

    //直接使用后台返回的签名数据  如果使用服务端的签名,把
    //下面的signApi()方法注释掉

// api.sig = "";
// api.sigType = "HMAC-SHA1";

    try {
        //为了测试,这里直接签名,此步骤放在服务端
        signApi(api);
    } catch (Exception e) {
        e.printStackTrace();
        Toast.makeText(mContext,"签名异常!",Toast.LENGTH_SHORT).show();
        return;
    }

    if (api.checkParams()) {
        openApi.execApi(api);
    }else{
        Toast.makeText(mContext,"支付参数有误!",Toast.LENGTH_SHORT).show();
    }

}

/**
 * 签名步骤建议不要在app上执行,要放在服务器上执行.
 */
public void signApi(PayApi api) throws Exception {
    // 按key排序 ASCII
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append("appId=").append(api.appId);
    stringBuilder.append("&bargainorId=").append(api.bargainorId);
    stringBuilder.append("&nonce=").append(api.nonce);
    stringBuilder.append("&pubAcc=").append("");
    stringBuilder.append("&tokenId=").append(api.tokenId);

    byte[] byteKey = (APP_KEY+"&").getBytes("UTF-8");
    // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
    SecretKey secretKey = new SecretKeySpec(byteKey, "HmacSHA1");
    // 生成一个指定 Mac 算法 的 Mac 对象
    Mac mac = Mac.getInstance("HmacSHA1");
    // 用给定密钥初始化 Mac 对象
    mac.init(secretKey);
    byte[] byteSrc = stringBuilder.toString().getBytes("UTF-8");
    // 完成 Mac 操作
    byte[] dst = mac.doFinal(byteSrc);
    // Base64
    api.sig = Base64.encodeToString(dst, Base64.NO_WRAP);
    api.sigType = "HMAC-SHA1";
}

/**
 *
 * QQ支付结果状态
 * */
public void onQQResponse(BaseResponse response){

    Log.i("QQPay","response.retCode="+response.retCode+",response.retMsg="+response.retMsg);

    if(response!=null){
        switch (response.retCode){
            case 0://支付成功
                if(mJPayListener!=null)
                    mJPayListener.onPaySuccess();
                break;
            case -1://支付取消 用户主动取消
                if(mJPayListener!=null)
                    mJPayListener.onPayCancel();
                break;
            case -2://登录超时
                if(mJPayListener!=null)
                    mJPayListener.onPayError(response.retCode,"登录超时");
                break;
            case -3://重复提交订单
                if(mJPayListener!=null)
                    mJPayListener.onPayError(response.retCode,"重复提交订单");
                break;
            case -4:
                if(mJPayListener!=null)
                    mJPayListener.onPayError(response.retCode,"快速注册用户手机号不一致");
                break;
            case -5:
                if(mJPayListener!=null)
                    mJPayListener.onPayError(response.retCode,"账号被冻结");
                break;
            case -6:
                if(mJPayListener!=null)
                    mJPayListener.onPayError(response.retCode,"支付密码输入超限");
                break;
            case -100:
                if(mJPayListener!=null)
                    mJPayListener.onPayError(response.retCode,"网络异常错误");
                break;
            case -101:
                if(mJPayListener!=null)
                    mJPayListener.onPayError(response.retCode,"支付参数错误");
                break;
            default:
                if(mJPayListener!=null)
                    mJPayListener.onPayError(response.retCode,"未知错误");

        }
    }
}

}

测试代码
orderQQ = "{"appid":"10445","mch_id":"1562271","nonce_str":"58d79b407a55b4af","prepay_id":"6M6c1a02c3b0e6c4","result_code":"SUCCESS","retcode":"0","retmsg":"ok","return_code":"SUCCESS","return_msg":"SUCCESS","sign":"638E931C4B13F7F","trade_type":"APP"}";

            if(TextUtils.isEmpty(orderQQ)){
                Toast.makeText(MainActivity.this,"预付订单为空",Toast.LENGTH_SHORT).show();
                return;
            }
            pay.payDoraVip(MainActivity.this,"PHP", JPay.PayMode.QQPAY,orderQQ);

JPay工具类,统一管理支付,好了,就写到这里,谢谢

有问题可以加我qq:215330802
项目地址:https://github.com/cammingcai/DoraPay

Unity 与Android 优化通信

https://www.jianshu.com/p/f5b20d43315a

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容