iOS开发热门-自动打包fastlane

使用fastlane工具自动打包发布App Store或蒲公英测试平台

 在以往的iOS开发过程中,我们大都使用xcode提供的工具进行手动打包ipa,这种打包方式会带来大量时间上的浪费,想必对于有追求的开发者来说时间都是宝贵的。那么,有没有一种方式可以通过一行指令自动完成打包呢?答案是:有的,通过笔者行走于江湖多年,得到了fastlane的这个开源的神器,可以到以下地址进行查看参考和学习:

 本篇文章将分为两大部分进行全面的讲解关于打包的内容:

  • 使用xcode提供的打包工具进行手动打包;
  • 使用fastlane工具进行自动打包;

 下面我们先来看下xcode工具的打包流程:
写在前面:本文中您所看到的效果都是基于xcode9.1进行的,当然,开发环境证书配置都是自动配置的,这里我不会再多赘述。
1.设置如图所示:

打包编译过程是需要消耗一定的时间的,视工程资源文件大小而定;
xcode工具打包.png
2.导出ipa包:
导出ipa.png
3.选择导出ipa包方式:
  • ad-hoc:打包发布蒲公英测试平台;
  • app-store:打包发布App Store;
  • 其他的签名方式在xcode9.0后是自动选择;
    选择导出ipa包方式.png
    4.将导出的ipa包存放到指定路径。
     到这里,打包的流程就完成了,下面我们就把导出的ipa通过xcode提供的上传工具进行发布app至App Store:
    上传ipa.png
    这一步也会进行对ipa进行编译,也是消耗时间的过程。。。
     至此,我们的ipa就会在iTunes content 中构建出新的版本,选择该版本上线即可;my friend ~这种操作,你能忍?!我可是忍不了!
    如果对于维护多个app或者多个target的工程,发布测试平台或者App Store来讲,这样的操作是令人崩溃的,那么,我们收拾下令人窒息的心情,请继续往下看~
     大家先来脑补一下这张图
    fastlane打包流程.png

     接下来,向大家详细的讲解fastlane自动打包,这里分以下 3 部分:
    1.单个工程使用fastlane自动打包
    2.针对多个target环境使用fastlane自动打包
    3.建议安装下蒲公英的mac客户端
    首先来看单个工程使用fastlane自动打包的流程及配置:
  • 使用fastlane环境打包,我们得先配置一下环境,fastlane是基于ruby的,所以我们需要安装下ruby环境,安装ruby环境参考此链接;
    *然后检查 Xcode 命令行工具是否安装。在终端窗口中输入命令:
  xcode-select --install

如果未安装,终端会开始安装,如果报错误:command line tools are already installed, use "Software Update" to install updates.代表已经安装。

  • 以上依赖配置好之后就可以通过 rubygem 进行安装了:
sudo gem install fastlane

安心等待一会,fastlane就安装完成了。

  • 接下来就是要初始化fastlane
    打开终端,cd到你的工程目录,然后执行fastlane init:
Peter-2:~ Peter$ cd desktop
Peter-2:desktop Peter$ cd Popo/
Peter-2:Popo Peter$ fastlane init
[⠋] 🚀 /Users/peter/.rvm/rubies/ruby-2.4.1/lib/ruby/gems/2.4.0/gems/tty-screen-0.6.4/lib/tty/version.rb:3: warning: already initialized constant TTY::Screen::VERSION
/Users/peter/.rvm/gems/ruby-2.4.1@global/gems/tty-screen-0.6.4/lib/tty/version.rb:3: warning: previous definition of VERSION was here
[✔] 🚀 
[✔] Looking for iOS and Android projects in current directory...
[17:08:01]: Created new folder './fastlane'.
[17:08:01]: Detected an iOS/macOS project in the current directory: 'Popo.xcodeproj'
[17:08:01]: -----------------------------
[17:08:01]: --- Welcome to fastlane 🚀 ---
[17:08:01]: -----------------------------
[17:08:01]: fastlane can help you with all kinds of automation for your mobile app
[17:08:01]: We recommend automating one task first, and then gradually automating more over time
[17:08:01]: What would you like to use fastlane for?
1. 📸  Automate screenshots
2. 👩‍✈️  Automate beta distribution to TestFlight
3. 🚀  Automate App Store distribution
4. 🛠  Manual setup - manually setup your project to automate your tasks
?  

写在当前:

  • 1、代表app市场图片素材;
  • 2、发布到TestFlight进行测试;
  • 3、发布到App Store;
  • 4、自定义
在初始化```fastlane```的过程中,可能会出现要输入苹果开发者账号,
在 "Your Apple ID" 这一步输入苹果开发者账号。
在“Please confirm the above values”这一步,确认信息,没问题输入 y。
然后,```fastlane ```会进行一系列的初始化操作,包括下载 App Store 上的元数据和截屏文件。

在这里,我们选择序号 4 ,来手动去设置自定义的打包内容,在这一步,你会发现新的世界~

?  4
[17:17:37]: ------------------------------------------------------------
[17:17:37]: --- Setting up fastlane so you can manually configure it ---
[17:17:37]: ------------------------------------------------------------
[17:17:37]: Installing dependencies for you...
[17:17:37]: $ bundle update
[17:17:48]: --------------------------------------------------------
[17:17:48]: --- ✅  Successfully generated fastlane configuration ---
[17:17:48]: --------------------------------------------------------
[17:17:48]: Generated Fastfile at path `./fastlane/Fastfile`
[17:17:48]: Generated Appfile at path `./fastlane/Appfile`
[17:17:48]: Gemfile and Gemfile.lock at path `Gemfile`
[17:17:48]: Please check the newly generated configuration files into git along with your project
[17:17:48]: This way everyone in your team can benefit from your fastlane setup
[17:17:48]: Continue by pressing Enter ⏎

[17:17:51]: fastlane will collect the number of errors for each action to detect integration issues
[17:17:51]: No sensitive/private information will be uploaded, more information: https://docs.fastlane.tools/#metrics
[17:17:51]: ----------------------
[17:17:51]: --- fastlane lanes ---
[17:17:51]: ----------------------
[17:17:51]: fastlane uses a `Fastfile` to store the automation configuration
[17:17:51]: Within that, you'll see different lanes.
[17:17:51]: Each is there to automate a different task, like screenshots, code signing, or pushing new releases
[17:17:51]: Continue by pressing Enter ⏎

[17:17:51]: --------------------------------------
[17:17:51]: --- How to customize your Fastfile ---
[17:17:51]: --------------------------------------
[17:17:51]: Use a text editor of your choice to open the newly created Fastfile and take a look
[17:17:51]: You can now edit the available lanes and actions to customize the setup to fit your needs
[17:17:51]: To get a list of all the available actions, open https://docs.fastlane.tools/actions
[17:17:51]: Continue by pressing Enter ⏎

[17:17:52]: ------------------------------
[17:17:52]: --- Where to go from here? ---
[17:17:52]: ------------------------------
[17:17:52]: 📸  Learn more about how to automatically generate localized App Store screenshots:
[17:17:52]:         https://docs.fastlane.tools/getting-started/ios/screenshots/
[17:17:52]: 👩‍✈️  Learn more about distribution to beta testing services:
[17:17:52]:         https://docs.fastlane.tools/getting-started/ios/beta-deployment/
[17:17:52]: 🚀  Learn more about how to automate the App Store release process:
[17:17:52]:         https://docs.fastlane.tools/getting-started/ios/appstore-deployment/
[17:17:52]: 👩‍⚕️  Learn more about how to setup code signing with fastlane
[17:17:52]:         https://docs.fastlane.tools/codesigning/getting-started/
[17:17:52]: 
[17:17:52]: To try your new fastlane setup, just enter and run
[17:17:52]: $ fastlane custom_lane

#######################################################################
# fastlane 2.88.0 is available. You are on 2.87.0.
# You should use the latest version.
# Please update using `sudo gem install fastlane`.
#######################################################################

2.88.0 Improvements
* [action] Fix crashlytics to not autoload gsp_path if api_token is set (#12176) via Josh Holtz
* Improve error message when specified scheme is not found (#12182) via Cédric Luthi
* [action] Support checking remote git tags existence (#11675) via Takeru Chuganji
* Use Android environment to find adb (don't just rely on it being in PATH) (#12168) via Adam Cohen-Rose
* [snapshot] Make sure matched window has a non-empty frame (#12174) via François Pradel
* [swift] Fixes string return value and shows all lanes (even without description) (#12171) via Josh Holtz
* [scan] Default skip_build to true in Scanfile template (#12162) via Aaron Brager

Please update using `sudo gem install fastlane`

等待初始化完成之后,工程目录下就多了一个 fastlane目录,其内容如下:

fastlane文件

初始化后,我们还需要添加一个蒲公英测试平台的插件以供提交测试,在终端输入fastlane add_plugin pgyer即可;
然后到工程目录下可以看到有个fastlane文件创建成功了,子目录里面有三个文件,一个Appfile,一个Fastfile文件,另一个Pluginfile,我们通过名称可知他们的大概用途:Appfile用来编辑设置app_identifier,apple_id和team_id的信息;Pluginfile是存放蒲公英测试平台的默认配置;Fastfile管理你所创建的 lane ,了解详情。它的格式是这样的:

#---------- begin -----------

default_platform :ios

  platform :ios do

    desc "发布 蒲公英"
    lane :beta_pgy do
      gym(scheme: "Test", 
          export_method: "ad-hoc",
          silent: true,  # 隐藏没有必要的信息
          clean: true  # 在构建前先clean
          )
      pgyer(api_key: "b*******************************4", 
            user_key: "e********************************7", 
            update_description: get_update_description(), 
           # password: "123456", 
           # install_type: "2"
        )
    end

    desc "发布 到 苹果TestFlight"
    lane :beta_apple do
      gym(scheme: "Test"],
          silent: true,  # 隐藏没有必要的信息
          clean: true  # 在构建前先clean
        )
      pilot #管理TestFlight测试用户,上传二进制文件
    end

    desc "发布苹果商店"
    lane :release_apple do
      
      gym(scheme: "Test"], 
          silent: true,  # 隐藏没有必要的信息
          clean: true  # 在构建前先clean
        )
      deliver #上传截图、元数据、App到iTunesConnect
    end

  #---------- end -------------

    # You can define as many lanes as you want

    after_all do |lane|
      # This block is called, only if the executed lane was successful

      # slack(
      #   message: "Successfully deployed new App Update."
      # )
    end

    error do |lane, exception|
      # slack(
      #   message: exception.message,
      #   success: false
      # )
    end
end

其中一个lane就是一个任务,里面是一个个的action组成的工作流。
利用目前支持的工具可以做所有包含自动化和可持续化构建的每个环节,例如:

  • scan 自动化测试工具,很好的封装了 Unit Test
  • sigh 针对于 iOS 项目开发证书和 Provision file 的下载工具
  • match 同步团队每个人的证书和 Provision file 的超赞工具
  • gym 针对于 iOS 编译打包生成 ipa 文件
  • deliver 用于上传应用的二进制代码,应用截屏和元数据到 App Store
  • snapshot 可以自动化iOS应用在每个设备上的本地化截屏过程

执行lane

定义完lane之后怎么执行呢?打开终端,切换到项目的根目录:执行fastlane lane'name就可以了。成功之后会在相应的路径下生成ipa文件,如果报错的话就根据错误信息好好查看文档
如果安装了mac版的蒲公英客户端的朋友,在自动打包完成之后,客户端会自动拦截ipa的动作(前提是保证你的账户和fastfile里面对于蒲公英的配置api_keyuser_key的配置保持一致即可)然后将ipa上传即可;

 怎么样,my friend,这一波操作下来是不是省去的时间可以去喝杯咖啡了。来来来,接下来就是多个target环境使用fastlane自动打包。这里分 3 部分来讲解配置:

  • 配置.env 文件(工程里面有几个traget,需要创建几个.env)
  • 配置 Deliverfile文件
  • 如何使用其进行打包
    比如工程里面有两个target(一个Test1,一个Test2),那么通过终端命令cd到上次初始化的fastlane目录,然后在终端输入touch .env.Test1touch .env.Test2,继续在当前目录下创建Deliverfiale,在终端输入touch Deliverfile,创建完成后,你会发现在fastlane目录下找不到刚刚创建的两个.env文件,可参考此文章,接下来对.env.Test1.env.Test2两个文件进行编辑;
    .env.Test1内容如下:
#APP唯一标识符
APP_IDENTIFIER = "com.Peter.Test1"

#发布版本号
APP_VERSION_RELEASE = "2.4.0"

#新版本修改记录
RELEASE_NOTES = "1) 升级测试第一行\n2) 升级测试第二行"

#蒲公英 更新描述
PGY_UPDATE_DESCRIPTION = "fastlane自动打包上传测试"

#自动提交审核
SUBMIT_FOR_REVIEW = false

#审核通过后立刻发布
AUTOMATIC_RELEASE = false

#苹果开发者账号
APPLE_ID = "XXXXXXXXXXXXXX"
#苹果开发者帐号密码
FASTLANE_PASSWORD = "*************"

#套装ID
TEAM_ID = "XXXXXXXXXXXXXX"

#应用名称
SCHEME_NAME = "Test1"

#APP元数据及截图存放路径
METADATA_PATH = "./metadata/Test1Copy"
SCREENSHOTS_PATH = "./screenshots/Test1Copy"

#APP元数据及截图下载时,直接覆盖原有数据,不询问
DELIVER_FORCE_OVERWRITE = true

.env.Test2内容如下:

#APP唯一标识符
APP_IDENTIFIER = "com.Peter.Test2"

#发布版本号
APP_VERSION_RELEASE = "2.4.1"

#新版本修改记录
RELEASE_NOTES = "1) 升级测试第一行\n2) 升级测试第二行"

#蒲公英 更新描述
PGY_UPDATE_DESCRIPTION = "fastlane自动打包上传测试"

#自动提交审核
SUBMIT_FOR_REVIEW = false

#审核通过后立刻发布
AUTOMATIC_RELEASE = false

#苹果开发者账号
APPLE_ID = "XXXXXXXXXXXXXXXXXXXXX"
#苹果开发者帐号密码
FASTLANE_PASSWORD = "****************"

#套装ID
TEAM_ID = "XXXXXXXXXXXXXXXXXXXXX"

#应用名称
SCHEME_NAME = "Test2"

#APP元数据及截图存放路径
METADATA_PATH = "./metadata/Test2Copy"
SCREENSHOTS_PATH = "./screenshots/Test2Copy"

#APP元数据及截图下载时,直接覆盖原有数据,不询问
DELIVER_FORCE_OVERWRITE = true

Deliverfile内容如下:

app_identifier ENV['APP_IDENTIFIER'] # The bundle identifier of your app
username ENV['APPLE_ID'] # your Apple ID user

# 元数据的路径
metadata_path ENV['METADATA_PATH']
screenshots_path ENV['SCREENSHOTS_PATH']

 #App store 中待发布的 App 版本,若每个 target 的版本号不同,可以通过.env 文件来分别定义
 app_version ENV['APP_VERSION_RELEASE']

 #下载 metadata 及 screenshots 时直接覆盖,不询问
 force true

 #不覆盖 iTunes Connect原有截图
 skip_screenshots true
    
 #自动提交审核
 submit_for_review ENV['SUBMIT_FOR_REVIEW']
  
 #审核通过后立刻发布
 automatic_release ENV['AUTOMATIC_RELEASE']

 #新版本修改记录
 release_notes({        
    "zh-Hans" => ENV['RELEASE_NOTES']
 })

Appfile内容如下:

# app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app
# apple_id("[[APPLE_ID]]") # Your Apple email address


# For more information about the Appfile, see:
#     https://docs.fastlane.tools/advanced/#appfile
 
app_identifier ENV['APP_IDENTIFIER'] # The bundle identifier of your app

apple_id ENV['APPLE_ID'] # Your Apple email address

team_id ENV['TEAM_ID'] # Developer Portal Team ID

Fastfile内容如下:


#---------- begin -----------

default_platform :ios

  platform :ios do

    desc "1).Test1版本 发布到 蒲公英"
    lane :beta_test1_pgy do
      sh "fastlane beta_pgy --env Test1"
    end

    desc "2).Test2版本 发布到 蒲公英"
    lane :beta_test2_pgy do
      sh "fastlane beta_pgy --env Test2"
    end

    desc "3).Test1版本 发布到 苹果商店"
    lane :release_test1_apple do
      sh "fastlane release_apple --env Test1"
    end

    desc "4).Test2版本 发布到 苹果商店"
    lane :release_test2_apple do
      sh "fastlane release_apple --env Test2"
    end

    desc "5).Test1版本 和 Test2版本 同时 发布到 蒲公英"
    lane :beta_all_pgy do
      sh "fastlane beta_pgy --env Test1"
      sh "fastlane beta_pgy --env Test2"
    end

    desc "6).Test1版本 和 Test2版本 同时 发布到 苹果TestFlight"
    lane :beta_all_apple do
      sh "fastlane beta_apple --env Test1"
      sh "fastlane beta_apple --env Test2"
    end

    desc "7).Test1版本 和 Test2版本 同时 发布到 苹果商店"
    lane :release_all_apple do
      sh "fastlane release_apple --env Test1"
      sh "fastlane release_apple --env Test2"
    end

    desc "发布 指定版本 到 蒲公英"
    lane :beta_pgy do
      gym(scheme: ENV['SCHEME_NAME'], 
          export_method: "ad-hoc",
          silent: true,  # 隐藏没有必要的信息
          clean: true  # 在构建前先clean
          )
      pgyer(api_key: "b******************************4", 
            user_key: "e*******************************7", 
            update_description: get_update_description(), 
           # password: "123456", 
           # install_type: "2"
        )
    end

    desc "发布 指定版本 到 苹果TestFlight"
    lane :beta_apple do
      
      gym(scheme: ENV['SCHEME_NAME'],
          silent: true,  # 隐藏没有必要的信息
          clean: true  # 在构建前先clean
        )
      pilot
    end

    desc "发布 指定版本 到 苹果商店"
    lane :release_apple do
      
      gym(scheme: ENV['SCHEME_NAME'], 
          silent: true,  # 隐藏没有必要的信息
          clean: true  # 在构建前先clean
        )
      deliver
    end

  #---------- end -------------

    # You can define as many lanes as you want

    after_all do |lane|
      # This block is called, only if the executed lane was successful

      # slack(
      #   message: "Successfully deployed new App Update."
      # )
    end

    error do |lane, exception|
      # slack(
      #   message: exception.message,
      #   success: false
      # )
    end
end

到这里,所有的配置都已经配置好了,另外还有一个需要设置的地方,在xcode开发工具中请将scheme的shared勾选上,如图:

设置scheme1.png

设置scheme2.png

紧接着,在终端用命令进入项目根目录,输入 fastlane ios
命令,效果如下:

fastlane ios
[✔] 🚀 
[22:28:04]: fastlane detected a Gemfile in the current directory
[22:28:04]: however it seems like you don't use `bundle exec`
[22:28:04]: to launch fastlane faster, please use
[22:28:04]: 
[22:28:04]: $ bundle exec fastlane ios
[22:28:04]: 
[22:28:04]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
[22:28:04]: In the config file './fastlane/Deliverfile' you have the line app_identifier, but didn't provide any value. Make sure to append a value right after the option name. Make sure to check the docs for more information
+-----------------------+---------+--------+
|               Used plugins               |
+-----------------------+---------+--------+
| Plugin                | Version | Action |
+-----------------------+---------+--------+
| fastlane-plugin-pgyer | 0.2.1   | pgyer  |
+-----------------------+---------+--------+

[22:28:04]: ------------------------------
[22:28:04]: --- Step: default_platform ---
[22:28:04]: ------------------------------
[22:28:04]: Welcome to fastlane! Here's what your app is setup to do:
+--------+-------------------------+----------------------------------------+
|                          Available lanes to run                           |
+--------+-------------------------+----------------------------------------+
| Number | Lane Name               | Description                            |
+--------+-------------------------+----------------------------------------+
| 1      | ios beta_test1_pgy      | 1).test1版本 发布到 蒲公英             |
| 2      | ios beta_test2_pgy      | 2).test2版本 发布到 蒲公英             |
| 3      | ios release_test1_apple | 3).test1版本 发布到 苹果商店           |
| 4      | ios release_test2_apple | 4).test2版本 发布到 苹果商店           |
| 5      | ios beta_all_pgy        | 5).test1版本 和 test2版本 同时 发布到  |
|        |                         | 蒲公英                                 |
| 6      | ios beta_all_apple      | 6).test1版本 和 test2版本 同时 发布到  |
|        |                         | 苹果TestFlight                         |
| 7      | ios release_all_apple   | 7).test1版本 和 test2版本 同时 发布到  |
|        |                         | 苹果商店                               |
| 8      | ios beta_pgy            | 发布 指定版本 到 蒲公英                |
| 9      | ios beta_apple          | 发布 指定版本 到 苹果TestFlight        |
| 10     | ios release_apple       | 发布 指定版本 到 苹果商店              |
| 0      | cancel                  | No selection, exit                     |
|        |                         | fastlane!                              |
+--------+-------------------------+----------------------------------------+
[22:28:04]: Which number would you like run?
1

此时,你想打什么包就打什么包,是不是很随心所欲呀?!

写在当前:前面说的推荐安装蒲公英客户端,为什么呢?请看这一波操作:
自动打包成功.png
fastlane刚编译成功,蒲公英客户端就马上进行ipa拦截,现在让我来发布一下看下成果:
fastlane自动打包发布蒲公英.png

由于时间的问题,我就不一一进行测试了,剩下的就交给各位朋友们自行测试看看效果。。。。
 亲们,如遇到问题可随时交流,欢迎来撩!

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

推荐阅读更多精彩内容