从零开始写个自动打包IPA脚本

背景

新项目这边每次版本移交,

给测试都是直接xcode挨个拿手机安装的流程.

一次两次还好,天天这么搞,而且每次一大波手机扔过来,瞬间觉得,自己好像是个疫苗注射员似的,顺次给每个手机打一针.

biu!

NEXT...

biu!

NEXT...

biu!

NEXT...

...

😢

...

于是..我崩溃了..

好吧,

是在是看不下去了,于是准备写个脚本以后自己打包,测试直接下载就好了.

思路

那么怎么实现这么一个事情呢?

其实上一家公司,做个类似的东西,虽不是我做的,但是大体流程还是知道的:

写个bash脚本,执行自动打包iOS版本,到指定的目录 (有条件的公司,可以自己搭个小服务器,这样谁都可以随时随地的打包)

将打包好的文件上传到fir.im (当然上传到自己公司的服务器或者任何地方都行,只是fir.im我一直用,觉得比较方便)

开发一个内部使用的类似APPStore,上面放着自己公司的所有APP,每次有更新的时候,测试童鞋直接通过这个自己下载新APP就可以了

开始做

1. 准备背景知识

其实当我们Xcode点击了build或者运行comand+R之后,Xcode自己执行的命令是xcodebuild这条命令.

然后,编译好之后,怎么生产ipa包?

用xcrun命令

话不多说,先上手:

打开终端,cd到你的工程位置,然后先试一下xcodebuild命令,

//xcrunchengpoleness@polenxcodebuild_iPA $ xcrun --versionxcrunversion29.//xcodebuildchengpoleness@polenios (develop) $ xcodebuild -versionXcode7.3Buildversion7D175

看上去很简单,大概了解了一下,就开始用:

chengpoleness@polenios (develop) $ xcodebuild2016-05-0213:05:04.623xcodebuild[1015:16272] [MT]PluginLoading:Required plug-incompatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362Cforplug-inat path'~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/XcodeColors.xcplugin'not presentinDVTPlugInCompatibilityUUIDs2016-05-0213:05:04.625xcodebuild[1015:16272] [MT]PluginLoading:Required plug-incompatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362Cforplug-inat path'~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/OMColorSense.xcplugin'not presentinDVTPlugInCompatibilityUUIDs=== BUILD TARGET xxx OF PROJECT xxx WITH THE DEFAULT CONFIGURATION (Release) ===Check dependenciesWrite auxiliary fileswrite-file/Users/chengpoleness/Documents/code/xxx/ios/build/xxx.build/Release-iphoneos/xxx.build/xxx.hmapwrite-file/Users/chengpoleness/Documents/code/xxx/ios/build/xxx.build/Release-iphoneos/xxx.build/xxx-own-target-headers.hmapwrite-file/Users/chengpoleness/Documents/code/xxx/ios/build/xxx.build/Release-iphoneos/xxx.build/Script-492B764475E022A63FB67F55.sh

接着满屏的快速滚动,可以看到clang依次在编译各个文件,登录大概十几秒闪屏,然后失败了!!!💔

ld: library not foundfor-lPodsclang: error: linker command failed withexitcode1(use -v to see invocation)** BUILD FAILED **The following build commands failed:    Ld build/xxx.build/Release-iphoneos/xxx.build/Objects-normal/armv7/xxx normal armv7    Ld build/xxx.build/Release-iphoneos/xxx.build/Objects-normal/arm64/xxx normal arm64(2failures)

这个就是找不到pods了,

为什么会这样?

自己直接用Xcode 亲自product-archive 了一遍,okey啊,没出现任何问题!

那是为什么呢?

各种goole,stackoveflow,但是基本说的是不要只打开project,而是打开workspace,其实这个是针对直接用xcode进行编译或者打包的时候,出现问题的解决方案,

然后尝试了其他解决方案,诸如ONLY_ACTIVE_ARCHS = NO等,都无效.

最终在下面这篇文章里,找到了灵感:

iOS Integration Tests With Appium

其实解决方案很简单,执行xcodebuild需要指定你所需要对应的workspace和scheme

所以命令如下:

xcodebuild -workspace/Users/chengpoleness/Documents/code/xxx/ios/xxx.xcworkspace -scheme xxx

执行前,先查看下-list,这个可以知道xcodebuild命令下对应的参数需要填写的内容

chengpoleness@polen ios (develop) $ xcodebuild -list2016-05-0215:24:26.656xcodebuild[16535:154176] [MT] PluginLoading: Required plug-incompatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362Cforplug-inat path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/XcodeColors.xcplugin'notpresentinDVTPlugInCompatibilityUUIDs2016-05-0215:24:26.661xcodebuild[16535:154176] [MT] PluginLoading: Required plug-incompatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362Cforplug-inat path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/OMColorSense.xcplugin'notpresentinDVTPlugInCompatibilityUUIDsInformation about project"xxx":    Targets:        xxx        xxxTests    Build Configurations:        DebugReleaseIfno buildconfigurationisspecifiedand-schemeisnotpassedthen"Release"isused.    Schemes:        xxx

然后,成功了,如下:

chengpoleness@polenios (develop) $ xcodebuild -workspace/Users/chengpoleness/Documents/code/xxx/ios/xxx.xcworkspace -scheme xxx2016-05-0215:26:29.627xcodebuild[16552:156501] [MT]PluginLoading:Required plug-incompatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362Cforplug-inat path'~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/XcodeColors.xcplugin'not presentinDVTPlugInCompatibilityUUIDs2016-05-0215:26:29.629xcodebuild[16552:156501] [MT]PluginLoading:Required plug-incompatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362Cforplug-inat path'~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/OMColorSense.xcplugin'not presentinDVTPlugInCompatibilityUUIDs=== BUILD TARGET Pods OF PROJECT Pods WITH CONFIGURATION Debug ===Check dependencies=== BUILD TARGET xxx OF PROJECT xxx WITH CONFIGURATION Debug ===Check dependenciesPhaseScriptExecution Check\ Pods\ Manifest.lock/Users/chengpoleness/Library/Developer/Xcode/DerivedData/xxx-djwnuzytnxhekrhjhypwxdqrxtet/Build/Intermediates/xxx.build/Debug-iphoneos/xxx.build/Script-492B764475E022A63FB67F55.sh.........Validate/Users/chengpoleness/Library/Developer/Xcode/DerivedData/xxx-djwnuzytnxhekrhjhypwxdqrxtet/Build/Products/Debug-iphoneos/xxx.app    cd/Users/chengpoleness/Documents/code/xxx/ios    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/Users/chengpoleness/.rvm/gems/ruby-2.0.0-p598/bin:/Users/chengpoleness/.rvm/gems/ruby-2.0.0-p598@global/bin:/Users/chengpoleness/.rvm/rubies/ruby-2.0.0-p598/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/chengpoleness/.rvm/bin:/usr/local/marven/apache-maven-3.3.9/bin:/Users/chengpoleness/Library/Android/sdk/platform-tools:/Users/chengpoleness/Library/Android/sdk/tools"export PRODUCT_TYPE=com.apple.product-type.application    builtin-validationUtility/Users/chengpoleness/Library/Developer/Xcode/DerivedData/xxx-djwnuzytnxhekrhjhypwxdqrxtet/Build/Products/Debug-iphoneos/xxx.app** BUILD SUCCEEDED **

2. 写脚本

(挑重点地说) 大致流程就是:

2.1 先git 指令,pull到最新的分支

这个很简单,没什么好说的了.

git clean -dfgitreset--hardgitfetchgit checkout $BRANCHNAMEgit pull--rebase origin $BRANCHNAMEecho"即将打包的分支log如下:"gitlog-5podupdate--verbose --no-repo-update

不过这几个指令,带有删除性,比如git clean -df,git reset 这种,所以用的时候要谨慎,如果你把脚本放在自己的工程目录下,就可能一不小心脚本就被删掉了(亲历者说...😢)

所以最终版本改成了

# git updategit checkout$BRANCHNAMEif[ $? -ne0]; thenexit1figit pull#pod update --verbose --no-repo-updateif[ $? -ne0]; thenexit1fi

只保留了checkout 和pull, pod没有用,是因为我们这边除了googleMap其他全是自造轮子,所以...并不需要😄.

2.2 xcodebuild进行编译

xcodebuild \-workspace $SORCEPATH/xxx.xcworkspace \-scheme $SCHEMENAMEPLQ \-configuration Debug \CODE_SIGN_IDENTITY="iPhone Developer: xxxx(T8TXPM5FC7)"  \PROVISIONING_PROFILE="5110ff0a-b845-475e-a4xxxxxxxxxx" \clean \build \-derivedDataPath $IPAPATH/$BRANCHNAME/$DATE

备注:

我这边因为是研发阶段,所以打包是debug包,如果是要打release 包,configuration中修改成Release,以及其他对应的修改下就行.

2.3 成功后xcrun打包成ipa包

xcrun -sdk iphoneos PackageApplication \        -v $IPAPATH/Build/Products/Debug-iphoneos/$SCHEMENAME.app \-o $IPAPATH/$IPANAME

最终脚本如下:

屏幕快照 2016-05-04 下午8.20.47.png

打包的文件命名我是按照时间来命名的,这样也方便找,尤其应对于可能分分钟就要突然来打包的测试团队.

3. 生成ipa包,上传到fir.im

3.1 fir比较好,有命令可以直接上传,但是需先安装fir-cli

安装过程如下:

chengpoleness@polenxcodebuild_iPA $ gem install fir-cliFetching:chunky_png-1.3.5.gem (100%)Successfully installed chunky_png-1.3.5Fetching:rqrcode-0.10.1.gem (100%)Successfully installed rqrcode-0.10.1......        ______________        ________    ____/ ____/_/ __ \      /____/ //  _// /_/ // /_/ /_____/ // // // __/_/ // _, _/_____/ /___/ /____/ //_//___/_/ |_|      \____/_____/___/......Installing ri documentationforthor-0.19.1Parsing documentationforfir-cli-1.4.9unable to convert"\xCE"from ASCII-8BIT to UTF-8forlib/fir/util/parser/bin/pngcrush, skippingInstalling ri documentationforfir-cli-1.4.913gems installed

安装如果遇到问题,可以到这里查看原因

3.2 使用fir指令,上传我们的ipa包

非常简单

firlogin -T c525718a775b954882xxxxxxxx      #fir.imtokenfirpublish $IPAPATH/Develop/xxx.ipa

3.3 扩展

另外,也可以直接用fir指令,进行打包或者编译,这个具体也没研究,其实就是对xcodebuild做了个封装,本质上还是执行那些指令,这里不再详述了.

chengpoleness@polen xcodebuild_iPA $ firCommands:  fir build_apk BUILD_DIR                      # Build Androidapp(alias: `ba`).  fir build_ipa BUILD_DIR [options] [settings]  # Build iOSapp(alias: `bi`).  firhelp#Describeavailable commands oronespecific command (aliase...  fir info APP_FILE_PATH                        # Show iOS/Androidappinfo, support ipa/apkfile(aliases: `...  fir login                                    # Login fir.im (aliases: `l`).  fir mapping MAPPING_FILE_PATH                # Uploadappmappingfileto BugHD.com (aliases: `m`).  fir me                                        # Show current user infoifuser is logined.  fir publish APP_FILE_PATH                    # Publish iOS/Androidappto fir.im, support ipa/apkfile(al...  fir upgrade                                  # Upgrade fir-cliand quit (aliases: `u`).  firversion# Show fir-cliversionnumber and quit (aliases: `v`).Options:  -T, [--token=TOKEN]              # User's APITokenat fir.im  -L, [--logfile=LOGFILE]          # Path to writable logfile  -V, [--verbose], [--no-verbose]  # Show verbose                                  # Default: true  -q, [--quiet], [--no-quiet]      # Silence commands  -h, [--help], [--no-help]        # Show thishelpmessage and quit

4. 测试一下

4.1 执行.sh文件

chengpoleness@polenxcodebuild_iPA$sh xcodebuild.sh

要是有比较懒的同学,直接把.sh文件,拖到命令行里面也行

4.2 过程与结果

编译过程的输出信息太多,删减了下,大概看一下流程:

chengpoleness@polen xcodebuild_iPA $ sh xcodebuild.sh HEAD is now at30865e1version3.5.0, build29Already on 'develop'......=== CLEAN TARGET Pods OF PROJECT Pods WITH CONFIGURATION Debug ====== CLEAN TARGET xxx OF PROJECT xxx WITH CONFIGURATION Debug ===......** BUILD SUCCEEDED **/* '以上是编译成功,接下来打包ipa'  */...Packaging application: '/Users/chengpoleness/Documents/code/xxx/buildiPA/develop/20160502_1801/Build/Products/Debug-iphoneos/xxx.app'Arguments: output=/Users/chengpoleness/Documents/code/xxx/buildiPA/develop/20160502_1801/1xxx_20160502_1801.ipa  verbose=1Environment variables:_system_name = OSX...### Checking original app...Done checking the original app...  adding: Payload/xxxx.app/xxxViewGpsOverlay.nib    (in=4889) (out=2502) (deflated49%)total bytes=53793797, compressed=23588024->56% savings]Results at 'xxxxxxxx/Documents/code/xxx/buildiPA/develop/20160502_1801/xxx_20160502_1801.ipa' /* '以上是打包成功,接下来是上传fir.im' */I, [2016-05-02T18:03:56.614082#47670]  INFO -- : Login succeed, current  user's email: xxxxI, [2016-05-02T18:03:56.614215#47670]  INFO -- : I, [2016-05-02T18:03:57.766434#47674]  INFO -- : Publishing app via chenglong.......I, [2016-05-02T18:03:57.766570#47674]  INFO -- : ✈ -------------------------------------------- ✈I, [2016-05-02T18:03:59.813783#47674]  INFO -- : Fetching com.osmgolf.xxx@fir.im uploading info......I, [2016-05-02T18:03:59.813868#47674]  INFO -- : Uploading app: xxx-3.5.0(Build29)I, [2016-05-02T18:04:00.562896#47674]  INFO -- : Uploading app icon......I, [2016-05-02T18:04:00.563029#47674]  INFO -- : Converting app's icon......I, [2016-05-02T18:04:01.715439#47674]  INFO -- : Uploading app binary......I, [2016-05-02T18:04:16.091891#47674]  INFO -- : Updating devices info......I, [2016-05-02T18:04:16.244710#47674]  INFO -- : Updating app info......I, [2016-05-02T18:04:16.514628#47674]  INFO -- : ✈ -------------------------------------------- ✈I, [2016-05-02T18:04:16.514862#47674]  INFO -- : Fetch app info from fir.imI, [2016-05-02T18:04:17.019304#47674]  INFO -- : Published succeed: http://fir.im/xxxxI, [2016-05-02T18:04:17.019409#47674]  INFO -- : 恭喜!!!上传fir.im成功!

OK,测试通过.

5.开发内部版“AppStore”

这个就这里不详述了,因为太简单.

写个tableview,把自己的app的链接放上去,每次有新版本了,通过这个App就可以下载,之前做过的截图如下:

至此,自动打包IPA的相关工作开发完成,可以投入使用了...

6 扩展-Debug/Release

6.1 背景:

目前的脚本打包都是默认打debug包的,但是如果我打Release包怎么办?如果我Debug包不同网络域名想切换怎么办?

6.2 Debug/Release

Okey,我们依次来解决这些问题:

其实很简单,xcodebuild指令有个-configuration, 我们使用这个决定是打Debug还是Release

那这个打出来的Debug和Release有什么区别呢?

这个相当于编译的时候是按照Debug模式或者Release模式来打包,从编译角度来说,区别挺大的,比如Debug会在某些堆栈环节预留更多的空间(我之前就遇到过同样的代码,但是Debug没问题,Release会有bug的情况,如果不知道这个的话,很难查出来或者理解这些bug,具体细节有空专门细说吧,这里不详述了)

所以,解决方案:定义一个CONGRUATION,根据传入的参数,决定打Debug还是打Release

# $1表示传入的第一个参数,启动脚本传入Debug或者Release就可以CONGRUATION=$1# 在xcodebuild和xrun的地方都使用$CONGRUATION即可xcodebuild \-workspace $SOURCEPATH/xxx.xcworkspace \-scheme $SCHEMENAME \-configuration $CONGRUATION \-derivedDataPath $IPAPATH \xcrun -sdk iphoneos PackageApplication \        -v $IPAPATH/Build/Products/$CONGRUATION-iphoneos/$SCHEMENAME.app \-o $IPAPATH/$IPANAME

6.2 Different Host 域名切换

这个其实解决方案很多:

方案A:

代码里写个Debug页面,里面设置可以切换不同的域名即可,

以前公司的APP就是这么做的,因为我们测算环境非常多,比如:

QA01,QA02,QA03...QA10...

所以直接在APP里就可以进行切换不同域名.

polen提醒:

1>  切换后一定要让用户退出,避免发生不必要的逻辑混乱

2> 需要设置个宏开关,确保Release版本用户100%走线上域名,Debug版本可以随意加各种逻辑判断.

务必避免如果代码不建壮,发生线上用户误入测试环境的悲剧 (当然,这个肯定属于bug了,严格是不应该发生的了,但是难免意外,没有东西是100%绝对的,这里只是提醒...)

方案B:

如果你们的测试环境没那么多,可能就2-3个,可以在打包的时候,通过脚本决定用哪个环境,具体怎么做:

CTO说怎么样能让脚本给代码传个值进入,然后代码在编译的时候根据这个值决定用哪个测试环境.

思考了很多方法,包括用脚本去改代码(硬改,用sed进入到.m文件修改,但这样太危险,而且很不友好)

后来学习到使用PREPROCESSOR_DEFINITIONS,就是xcode在打包前会先从 一个config中读取一些配置信息,这些在xcode-building里面可以直接设置,自然也可以通过xcodebuild指定穿进去,传入的就是GCC_PREPROCESSOR_DEFINITIONS

所以就是:

设定一个SERVER_TYPE宏定义,如果#ifdef  SERVER_TYPE的话,使用传入的参数,否则使用代码自定义的逻辑

# $serverType是启动脚本传入的参数值if[$CONGRUATION= Debug ];thenPREPROCESSOR_DEFINITIONS="COCOAPODS=1 SERVER_TYPE=$serverTypeDEBUG=1"elsePREPROCESSOR_DEFINITIONS="COCOAPODS=1 SERVER_TYPE=$serverType"fixcodebuild \-workspace$SOURCEPATH/xxx.xcworkspace \-scheme$SCHEMENAME\GCC_PREPROCESSOR_DEFINITIONS="$PREPROCESSOR_DEFINITIONS"\-configuration$CONGRUATION\-derivedDataPath$IPAPATH\

具体代码中如何使用:

//HOST_TYPE决定最终的域名#ifdefSERVER_TYPE#defineHOST_TYPE SERVER_TYPE#else#ifdefDEBUG#defineHOST_TYPE HOST_TYPE_CANARY#else#defineHOST_TYPE HOST_TYPE_PRODUCTION#endif#endif

okey,以上就解决了Debug和Release相关的问题

7.遇到的一些疑难杂症

br>

7.1 SDK不匹配导致编译失败

7.1.1 背景

下午(2016.8.2)正在忙,突然测试同学跑过来,大喊:“不好了,不好了...”

我以为要说台风来了,(做好了可以下班的准备..😄)

结果,来了句:

“打包脚本失败了,失败了!!”

我擦,啥情况,用了几个月了好好的,突然就失败了...

7.1.1 原因

后来确认下来是这么个情况,iOS10发布了,之前一直拖延,最近不是很忙了,于是有同事下载了xcode8-beta3和iOS10的安装profile。

然而iOS10的SDK更新,导致我们有个代码逻辑无法实现,于是Fix了一下,然后继续交给测试同学打包测试,结果就打包失败了,我看了下失败原因:

error:property 'firstAnchor' not found on object of type 'NSLayoutConstraint *'      object_setIvar(constraint.firstAnchor, referenceItem, view);

屏幕快照 2016-08-02 下午5.44.54.png

然后查了下代码,代码逻辑应该是没问题的。而找不到这个property是因为这个代码使用的iOS10的SDK,用旧版本自然是找不到,然后问了下测试,直接用xcode编译可以么?回答说可以。

那分析下来就应该是路径的问题了.

去她位置上看了下,(因为我自己没装xcode8,所以自己没法调试).一看发现问题了,她目前是两个xcode都在,但一个叫Xcode,一个叫Xcode-beta,脚本跑起来的时候,SDK肯定还跑得是以前的xcode的啊,自然编不过,于是改了一下名字,把原来的Xcode改为Xcode7,新的Xcode-beta改为Xcode.

然后,问题解决!😄

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

推荐阅读更多精彩内容