Jenkins一:iOS自动打包完整实践

后续文章:Jenkins二:参数化构建iOS自动打包
快捷记录:如果jenkins是用dmg安装,因为权限问题不能访问keychain时,每次新添加一个p12文件都要如此,
/Users/管理员用户名/Library/keychains/login.keychain-db
将login.keychain-db复制一份并命名为login.keyain复制到
/Users/Shared/Jenkins/Library/Keychains/login.keychain
同时要在

前言 :

因团队发展涉及到需要把打包工作配置好自动打包后移交给测试团队,网上资料很多,找了几篇文章在我自己的MacBook Pro上跟着一步步安装下来,虽然也遇到几个问题,但很快就找到了解决方案最后成功自动打包成功,于是就在一台专门的打包电脑Mac mini上安装环境,因为都是随机在网上找的资料,结果两次安装环境步骤稍微不一样,第一次是使用homebrew安装的,安装在默认账户下,没遇到什么权限问题,第二次在mac mini上安装使用的是安装包的方式,遇到一系列问题,大部分问题跟权限有关。陆陆续续查找解决构建了200多次,持续了2个周

参考资料:


强烈建议使用homedrew安装会省却很多权限问题,如果用pkg安装包安装,会被权限问题折腾掉半条命
强烈建议二:通过在做Master-Slave配置节点打包时发现使用Tomcat里安装war包的方式安装Jenkins的方式更方便快捷

Jenkins十:Mac通过 Tomcat里安装Jenkins配置Master-Slave打包iOS并上传到svn服务器

一、安装jenkins

前提条件:已经安装homedrew、Java

  • Mac终端软件安装利器:Homebrew
  • 如何在mac上安装java1.8
    通过homedrew安装jenkins命令
    brew install jenkins
    通过homedrew安装后jenkins安装好后所在的位置:
    实际安装位置:/usr/local/Cellar/jenkins/
    配置文件所在位置:/usr/local/opt/jenkins/
    工作空间位置:/Users/用户/.jenkins
    进入工作空间位置:cd ~/.jenkins
二、设置开机自启动:
方式一、将启动plist在LaunchAgents创建一个链接镜像(ln是创建一个link的意思)

1.1,创建一个链接到开机启动文件家里
ln -sfv /usr/local/opt/jenkins/*.plist ~/Library/LaunchAgents
1.2:手动启动jenkins
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.jenkins.plist
1.3 手动关闭jenkins
launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.jenkins.plist
1.4 根据需求修改jenkins的启动端口,修改/usr/local/Cellar/jenkins/2.149/homebrew.mxcl.jenkins.plist即可
修改后重新启动可能会报如下错误:

/usr/local/Cellar/jenkins/2.149/homebrew.mxcl.jenkins.plist: Path had bad ownership/permissions

执行以下的两个命令行:

sudo chown root /usr/local/Cellar/jenkins/2.149/homebrew.mxcl.jenkins.plist
sudo chgrp wheel /usr/local/Cellar/jenkins/2.149/homebrew.mxcl.jenkins.plist
方式二(缺点:执行shell的termenal一直在前台运行,不小心关掉了就会停止,有强迫症爱干净的人也不喜欢多一个不能关掉的termenal窗口)

添加一个启动执行的shell文件
2.1:在/usr/local/opt/jenkins创建一个jenkinsBoot.sh文件,内容如下

#!/bin/sh
#默认是8080端口,这里指定为8888端口启动
jenkins --httpPort=8888

2.2:打开系统偏好设置->用户与群组->当前管理员->登录项->+/usr/local/opt/jenkins/jenkinsBoot.sh加入到这里来


常用默认参数:${WORKSPACE}${HOME}
查找正在运行的jenkins并关闭:

#查找正在运行的jenkins服务,查看jenkins.war那一行的端口号
ps -ef | grep jenkins
 501 82363 22132   0 12:33PM ttys000    0:00.00 grep jenkins
 501   926   855   0 Fri06PM ttys002    0:00.00 /bin/sh /usr/local/Cellar/jenkins/2.149/jenkinsBoot.sh
  501   xxxx   926   0 Fri06PM ttys002    6:58.53 /usr/bin/java -jar /usr/local/Cellar/jenkins/2.149/libexec/jenkins.war
#关闭jenkins.war那一行的端口号对应的服务
kill -int xxxx

应注意一个读者在配置jenkins环境时,配置keychain时的问题

说明:要jenkins打包iOS的ipa需要苹果系统支持,也就是说安装jenkins的机器是苹果系统或能用jenkins配置一台能访问的苹果系统的电脑作为master机器(本文以默认jenkins所在的机器就是苹果系统)

1、下载发布证书或从开发人员那里拿到导出的发布证书p12

  • 一个苹果证书怎么多次使用——导出p12文件
    双击安装证书后,jenkins所在的机器就有发布证书了
    login.keychain位置:
    /Users/管理员用户名/Library/keychains/login.keychain-db
    将login.keychain-db复制一份并命名为login.keyain
    描述文件位置:
    /Users/管理员用户名/Library/MobileDevice/Provisioning Profiles
    (不建议从这里找,因为上传这里的描述文件之后看到的标题也是UUID格式,所以最好单独上传从苹果开发网站下载的描述文件,或者把下面的描述证书拷贝出来改个名再上传)

2、将证书上传到jenkins里
将1中复制的login.keychain上传到这里,如下图所示,
identities:找keychain里这个发布证书的内容


image.png
image.png

【Mac】解决jenkins执行shell脚本等场景中遇见的权限不足问题
******以上解决权限问题的方式会有异常问题,不能这样做
实际的过程,以要使用git为例

#1、切换到jenkins用户下
#[mac终端切换用户](https://blog.csdn.net/doudou19930614/article/details/81410823)
su - Jenkins
#2、创建一个文件夹
mkdir xxx
#3、clone对应的git
git clone xxxxxx
#4、为了不用在每次push到GitHub上时都输入用户名密码
#[mac下git push避免每次都输入用户名和密码的配置](https://www.cnblogs.com/zhaoshunjie/p/6306927.html)
#5、如果有提示需要输入全局的账号和邮箱
# 设置提交代码时的用户信息
git config --global user.name "[name]"
git config --global user.email "[email address]"
#后续其他以jenkins账号操作都正常了

一、使用Jenkins自动打iOS安装包前提条件

1、Mac OS系统(我所使用的是MacBook Pro 和Mac mini)
2、Xcode
3、cocoapods(非必须,如果使用cocoapod管理第三方库才需要)
4、Java
5、sourcetree(git管理工具非必须,我主要用来看代码有没有问题)
6、cornerstone(svn管理工具非必须,我主要用来讲打包的ipa文件上传到SVN上,而不是通常的放到第三方服务器)
7、Jenkins(homebrew安装方式和安装包安装方式两种)

二、使用Jenkins安装包安装方式遇到的问题

1、提示

Failed to connect to repository : Command "git -c core.askpass=true ls-remote -h git@XXXXX:XXXX/XXXX.git HEAD" returned status code 128:

image.png

原因:

由于使用Jenkins安装包安装,不能直接使用http的方式为git地址(why?),需要切换成ssh地址,ssh地址需要配置秘钥

解决办法:

配置ssh秘钥参考文章解决在Mac下搭建Jenkins+GitLab持续集成环境踩到的坑(一)

2、提示

Code Signing Error: No certificate for team 'xxxxx' matching 'iPhone Distribution: xxxxx.' found: Select a different signing certificate for CODE_SIGN_IDENTITY, a team that matches your selected certificate, or switch to automatic provisioning.

原因:

由于使用Jenkins安装包安装,在安装时创建了一个新的用户,默认放在钥匙串里的证书Jenkins这个用户访问不了

解决办法:

将钥匙串下的 登录里的相关证书拷贝到 钥匙串下的 系统里面

3、提示

Run custom shell script '[cp] embed pods frameworks ..... errSecInternalComponent.

/usr/bin/codesign --force --sign DC8791E5F036D9BAAFEC8E347093A20EB435BF0F --preserve-metadata=identifier,entitlements '/Users/Shared/Jenkins/Home/workspace/iOSDev/Release-iphoneos/xxx.app/Frameworks/AFNetworking.framework'
/Users/Shared/Jenkins/Home/workspace/iOSDev/Release-iphoneos/xxx.app/Frameworks/AFNetworking.framework: errSecInternalComponent

Command /bin/sh failed with exit code 1

** BUILD FAILED **

The following build commands failed:
PhaseScriptExecution [CP]\ Embed\ Pods\ Frameworks /Users/Shared/Jenkins/Library/Developer/Xcode/DerivedData/Lottery-dubolgbhbwxukkfsjmthrywdixge/Build/Intermediates.noindex/Lottery.build/Release-iphoneos/xxx.build/Script-79402CD10148DF169F37FF35.sh
(1 failure)
Build step '执行 shell' marked build as failure
[OS X] restore keychains as defined in global configuration
[iOSDev] $ /usr/bin/security list-keychains -s /Users/Shared/Jenkins/Library/Keychains/login.keychain
Finished: FAILURE


image.png
原因一:

看了一篇文章Run custom shell script '[cp] embed pods frameworks ..... errSecInternalComponent,按着里面的操作后并没解决问题,

解决办法:

看到--force --sign的字样猜测还是权限的问题,于是我把拷贝到钥匙串->系统 下的那个证书设置为 始终信任,顺利解决问题
如果还不可以则:
xcodebuild -workspace .....前添加一行解锁login.keychain的命令
security unlock-keychain -p 个人的账号登录密码 /Users/Shared/Jenkins/Library/Keychains/login.keychain

原因二:

在要用一个新appleID开发者账号创建一个新target时,电脑的login.kechain-db已经重新生成或者说修改了,但之前配置在Jenkins里的还是旧的,所以需要重新将login.keychain-db复制一份并重命名为login.kehchain上传到Jenkins里忘了在Jenkins配置时Keychains and Provisioning Profiles Management->Keychains
,同时将login.keychain-db、login.keychain拷贝到Jenkins的对应目录下,我的目录为:/Users/xxxx/Library/Keychains -> /Users/Shared/Jenkins/Library/Keychains
4、提示

xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH

原因:

新版的Xcode里没有想过的工具库

解决办法:

参考:xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH
顺便由于提示warning: PackageApplication is deprecated, use ``xcodebuild -exportArchive`` instead.,这个根据提示替换修改下就好了

5、提示

Build step '执行 shell' marked build as failure
[OS X] restore keychains as defined in global configuration

原因:

Jenkins用户权限比较低,不能使用login.keychain

解决办法:

xcodebuild -workspace .....前添加一行解锁login.keychain的命令
security unlock-keychain -p 个人的账号登录密码 /Users/Shared/Jenkins/Library/Keychains/login.keychain

6、提示

=== BUILD TARGET xxxx OF PROJECT Lottery WITH CONFIGURATION Release ===

Check dependencies
Code Signing Error: "xxxx" requires a provisioning profile with the Push Notifications feature. Select a provisioning profile for the "Release" build configuration in the project editor.
Code Signing Error: Code signing is required for product type 'Application' in SDK 'iOS 11.4'

** BUILD FAILED **

原因一:

该target的build setting配置不正确,之前是将Code Signing Identity统一配置成iOS Distribution了,这种方式在xcode里手动点击archive打包时没问题,但使用Jenkins自动打包就出报上面的错

image.png

解决办法:

将报错的这个targetbuild setting设置为精确的描述证书,比如iPhone Distribution: xxxxx,如下图:

image.png

另外之前查找资料时发现一些相关的资料,但没有解决我的问题
Jenkins+XCode9自动打包错误处理
最全Jenkins+SVN+iOS+cocoapods环境搭建及其错误汇总

7、提示

error: Unable to create '/Users/admin/Documents/svn/docs/xxxx.ipa'

原因:

这个路径是为了设置将打包出来的ipa安装包自动放到SVN路径下然后自动上传到SVN服务器,但还是由于打包Jenkins用的是一个独立的用户导致的权限问题

解决办法:

将/Users/admin/Documents/svn/docs/这个路径的每一个文件夹都设置为所有用户有读写权限

花了两个周构建几百次的血的教训,建议还是都用homebrew的方式安装少些权限问题

end
配置的参数:


多个scheme的配置

Debug/Release

git分支和tag选择

参数配置的使用页面

完整构建脚本:

# 工程名
APP_NAME="xxxx"


#***************动态配置部分*********************
# 不勾上自动管理证书
CODE_SIGN_DISTRIBUTION="iPhone Distribution: xxxxx"
# 代码文件夹名称,这是由于源码并不在git项目的根目录下
code_folder="xxxx"
#scheme#Info文件名称#保存ipa文件夹
platformParams=(${iOS_PLATFORM//\#/ })
# schema名称
SCHEMECA=${platformParams[0]}
#info.plist文件名称
INFO_FILENAME=${platformParams[1]}
# 输出到svn的文件夹名称
OUT_SVN_FOLDER=${platformParams[2]}
#*************************************
project_path=""
project_infoplist_path="./${code_folder}/Resource/platforms/${INFO_FILENAME}.plist"

#取版本号
bundleShortVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" "${project_infoplist_path}")

#取build值
bundleVersion=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" "${project_infoplist_path}")
#取bundleId
bundleId=$(/usr/libexec/PlistBuddy -c "print CFBundleIdentifier" "${project_infoplist_path}")
DATE="$(date +%Y%m%d-%H%M%S)"
#唯一名称ipa、dsYM文件名
UNIQUE_NAME="${APP_NAME}_${SCHEMECA}_${iOS_Release}_V${bundleShortVersion}_${DATE}"
IPANAME="${UNIQUE_NAME}.ipa"
#根据需求定义输入ipa的文件夹位置
PARENT_FOLDER="$HOME/testJenkins/test/study/${OUT_SVN_FOLDER}"

if [ ! -d $PARENT_FOLDER  ];then
  mkdir -p $PARENT_FOLDER
else
  echo dir exist
fi
#要上传的ipa文件路径
IPA_PATH="$PARENT_FOLDER/${IPANAME}"
echo ${IPA_PATH}
echo "${IPA_PATH}">> text.txt

#下面2行是没有Cocopods的用法
#echo "=================clean================="
#xcodebuild -target "${TARGET_NAME}"  -configuration 'Release' clean
#
#echo "+++++++++++++++++build+++++++++++++++++"
#xcodebuild -target "${TARGET_NAME}" -sdk iphoneos -configuration 'Release'  CODE_SIGN_IDENTITY="${CODE_SIGN_DISTRIBUTION}" SYMROOT='$(PWD)'

#下面2行是集成有Cocopods的用法
echo "=================clean================="
xcodebuild -workspace "./${code_folder}/${APP_NAME}.xcworkspace" -scheme ${SCHEMECA}  -configuration "${iOS_Release}" clean


echo "+++++++++++++++++build+++++++++++++++++"
xcodebuild -workspace "./${code_folder}/${APP_NAME}.xcworkspace" -scheme ${SCHEMECA} -sdk iphoneos -configuration "${iOS_Release}" CODE_SIGN_IDENTITY="${CODE_SIGN_DISTRIBUTION}" SYMROOT='$(PWD)' -allowProvisioningUpdates



xcrun -sdk iphoneos PackageApplication "./${iOS_Release}-iphoneos/${SCHEMECA}.app" -o ${IPA_PATH}
#生成dsYM文件
dsymutil "./${iOS_Release}-iphoneos/${SCHEMECA}.app/${SCHEMECA}" -o "${PARENT_FOLDER}/${UNIQUE_NAME}.app.dSYM"
cd "${PARENT_FOLDER}"
if [ ! -d "${UNIQUE_NAME}.app.dSYM"  ];then
  echo "没有可以压缩的dsYM文件"
else
 #压缩dsYM文件
  zip -q -r -m -o "${UNIQUE_NAME}.app.dSYM.zip" "${UNIQUE_NAME}.app.dSYM"
  #上传dsYM文件到解析平台
  #curl -k "https://api.bugly.qq.com/openapi/file/upload/symbol?app_key=xxxxxx&app_id=xxxxxx" --form "api_version=1" --form "app_id=xxxxxx" --form "app_key=xxxxxx" --form "symbolType=2"  --form "bundleId=${bundleId}" --form "productVersion=${bundleShortVersion}" --form "channel=xxx" --form "fileName=${UNIQUE_NAME}.app.dSYM.zip" --form "file=@${UNIQUE_NAME}.app.dSYM.zip" --verbose
fi
# 将生成的ipa上传到SVN
#cd "/Users/tony/Documents/svn/docs/svn/"
#svn upgrade
#svn add ${IPA_PATH}
#svn commit -m "add test" ${IPA_PATH} 

三、使用homebrew安装方式遇到的问题

自动打包实践:
一、Jenkins自动打包管理,参考教程如下:
手把手教你利用Jenkins持续集成iOS项目
iOS开发-自动化打包Jenkins集成
jenkins - iOS自动化打包分发
iOS自动化打包实战(Jenkins)
Jenkins安装、配置、构建、脚本、配置邮箱、上传fir
Mac下Jenkins+SVN(Git)+Xcode搭建持续构建环境
Mac jenkins 开机启动设置

选择指定的tag自动脚本打包
Confluence-Documention

二、遇到问题

FATAL: String index out of range: 15
java.lang.StringIndexOutOfBoundsException: String index out of range: 15
at java.lang.String.substring(String.java:1963)
at com.sic.plugins.kpp.provider.KPPBaseProvisioningProfilesProvider.removeUUIDFromFileName(KPPBaseProvisioningProfilesProvider.java:171)
at com.sic.plugins.kpp.model.KPPProvisioningProfile.getProvisioningProfileFilePath(KPPProvisioningProfile.java:76)
at com.sic.plugins.kpp.KPPProvisioningProfilesBuildWrapper.copyProvisioningProfiles(KPPProvisioningProfilesBuildWrapper.java:157)
at com.sic.plugins.kpp.KPPProvisioningProfilesBuildWrapper.setUp(KPPProvisioningProfilesBuildWrapper.java:99)
at hudson.model.BuildBuildExecution.doRun(Build.java:157) at hudson.model.AbstractBuildAbstractBuildExecution.run(AbstractBuild.java:504)
at hudson.model.Run.execute(Run.java:1794)
at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
at hudson.model.ResourceController.execute(ResourceController.java:97)
at hudson.model.Executor.run(Executor.java:429)
Finished: FAILURE

这是因为当时没有在Keychains and Provisioning Profiles Management里面上传配置文件导致的,
上传配置文件的方法和上传login.keychain一样,
选择那个配置文件,点击upload,
配置文件存在你电脑的
`/Users/‘电脑用户名称’/Library/MobileDevice/Provisioning Profiles`目录下。

xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH
后面根据对比发现新版的Xcode少了这个PackageApplication
先去找个旧版的Xcode里面copy一份过来
放到下面这个目录:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/
然后执行命令
sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer/
再执行
chmod +x /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/PackageApplication

最后附上PackageApplication下载地址:
https://pan.baidu.com/s/1jHJF2Lo

mac系统命令行curl详解

遇到问题

Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_XXXX", referenced from:
      objc-class-ref in XXXX.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

** BUILD FAILED **

原因:
当前target没有把XXXX这个文件的.m文件没有勾选到Target MemberShip
这种问题特别容易出现在一个项目有多个target的时候
如下:

tmp633006ba.png

解决办法:
将提示的文件勾选到Target MemberShip

问题:

Warning: unable to build chain to self-signed root for signer "iPhone Distribution: "/Users/Shared/Jenkins/Home/workspace/xxx/Release-iphoneos/xxx.app/Frameworks/AFNetworking.framework: errSecInternalComponent
Command /bin/sh failed with exit code 1

** BUILD FAILED ** 

如果没有这个插件,先安装插件
Jenkins->Jenkins管理->插件管理->可选插件 输入:Keychains and Provisioning Profiles Management,找到这个插件,然后点击直接安装


tmp316b3fcb.png

原因:
忘记把新添加的p12证书对应的Identity添加到Jenkins->系统管理->Keychains and Provisioning Profiles Management->Add code Signing Identity里,

tmp2cbdfdaa.png

点击:选取文件->Upload->保存
依次将Jenkins所在的机器的login.keychain(/Users/管理员用户名/Library/keychains/login.keychain-db 复制一份改名成成login.keychain),
需要管理的描述文件xxx.mobileprovision上传保存


Mac 开启Apache服务器及PHP环境
Mac下配置Apache服务器
搭建企业账号ipa包分发下载平台
Mac中开启Apache的Https功能
Mac Security工具使用总结find-identity

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

推荐阅读更多精彩内容