Jenkins+Fastlane+自动化打包+蒲公英二维码展示+邮件通知+飞书机器人

前期准备

1.ruby环境

fastlane的安装需要Ruby2.0版本以上,虽然mac自带ruby,但是版本可能较低,并且权限较少,所以推荐使用RVM管理ruby版本。
按照这篇文章安装就可以了Mac安装Ruby版本管理控制器

2.Xcode命令行工具

xcode-select --install 

如果已经安装会提示如下信息

xcode-select: error: command line tools are already installed, use "Software Update" to install updates

未安装提示如图所示


xcode安装.png

直接点击安装就可以了,安装完成后再次执行 xcode-select --install 之后出现已经安装的提示了。

3.Java JDK(jenkins安装会使用)

可以先查看当前安装的Java版本

 java -version

如果未安装请先前往JDK下载链接下载
因为jenkins是用java语言编写的,所以需要java环境支持

WechatIMG47.jpeg

下载完直接安装就可以了

4.Python (Python调用Jenkins API获取构建结果发通知需要)
直接上python官网下载
或者通过Homebrew安装python3
brew install python3

查看python3版本号

python3 --version

查看python3安装的路径

which python3

根据pyhon3安装的路径配置 bashrc 或者zprofile(我安装了iTerm及oh-my-zsh插件)文件

 #fastlane
  export LC_ALL=en_US.UTF-8
  export LANG=en_US.UTF-8

# Setting PATH for HOMEBREW
  export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles #ckbrew
  eval $(/usr/local/Homebrew/bin/brew shellenv) #ckbrew

# Setting PATH for JAVA
  export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-17.0.4.1.jdk/Contents/Home
  export PATH=$JAVA_HOME/bin:$PATH:.
  export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:.


# Setting PATH for Python 3.10.8  (brew install python3)
#  export PATH=${PATH}:/usr/local/Frameworks/Python.framework/Versions/3.10/bin/python3.10
#  alias python="/usr/local/Frameworks/Python.framework/Versions/3.10/bin/python3.10"


# Setting PATH for Python 3.11 (手动下载python3.11的包安装自动生成的路径)
# The original version is saved in .zprofile.pysave
  PATH="/Library/Frameworks/Python.framework/Versions/3.11/bin:${PATH}"
  export PATH
  alias python=PATH

终端截图如下:


WechatIMG49.jpeg

fastlane

fastlane是为iOS和Android应用程序自动化beta部署和发布最简单的方法。🚀可以处理各种繁琐任务,例如生成屏幕截图,处理代码签名和发布应用该程序等.fastlane整合了一系列移动端开发中签名,编译,发布等工具,堪称打包神器.
fastlane可以单独在项目中使用,也可以配合jenkins搭配使用

fastlane安装的三种方式
1.Homebrew
brew cask install fastlane
2.RubyGems
gem install fastlane -NV

初始化

cd  /到自己的项目目录下
#初始化
fastlane init
#添加fastlane蒲公英插件(初始化完成之后再执行下面命令)
#Fastlane 安装成功之后 执行安装蒲公英的插件
#jenkins上传蒲公英为了获取下载二维码,而采用了jenkins的插件(Upload to pgyer),如果fastlane不单独使用,可以忽略fastlane蒲公英插件
fastlane add_plugin pgyer
fastlane init.png

1.Automate screenshots: 自动截屏
2.Automate beta distribution to TestFlight: 自动发布beta版本到testFlight
3.Automate App Store distribution: 自动发布到App Store
4.Manual setup: 手动设置
这里我们选择第4个
成功之后,打开我们的项目目录发现多了这个文件


fast file.png

配置Fastlane

文件名 描述
Appfile 从 Apple Developer Portal 获取和项目相关的信息 详情
Fastfile 核心文件,存放lane任务
Deliverfile deliver的配置文件,从 iTunes Connect 获取和项目相关的信息详细
metadata 同步iTC中的元数据
screenshots 同步iTC中的截图

这里给打家推荐一篇配置的文章Fastfile参考配置
下面是我的配置仅供参考,没有用fastlane上传蒲公英,因为想要在jenkins里面获取二维码暂时的解决办法使用jenkins上传蒲公英 如果需要fastlane上传直接打开的注释进行了

# 导出路径
$ipa_output_directory = "/Users/xx/xx/fastlaneBuild"
# 上传蒲公英的包 路径
$ipa_output_upload_directory = "/Users/xx/.jenkins/workspace/xx/ipa"
# jenkins匹配的包名
$jenkins_name = "项目名"

default_platform(:iOS)
   # 应用名词
   scheme_name = "项目名字"
    # 获取version
   version = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleShortVersionString")
   # 获取build版本号
   build = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleVersion")
   # 指定xcode打包 这里可选择不要,我们的项目需要用10.1版本xcode
   xcode_select("/Applications/Xcode_10.1.app")
   # 默认内测打包方式,目前支持app-store, package, ad-hoc, enterprise, development
   ipa_exportMethod = "ad-hoc"
   ipa_exportMethod_appStore = "app-store"

# 计算buildNumber
def updateProjectBuildNumber
   currentTime = Time.new.strftime("%Y%m%d")
   scheme_name = "项目名字"
       build = get_info_plist_value(path: "./#{scheme_name}/Info.plist", key: "CFBundleVersion").to_s
   if build.include?"#{currentTime}."
   # 为当天版本 计算迭代版本号
       lastStr = build[build.length-2..build.length-1]
       lastNum = lastStr.to_i
       lastNum = lastNum + 1
       lastStr = lastNum.to_s
       if lastNum < 10
           lastStr = lastStr.insert(0,"0")
       end
       build = "#{currentTime}.#{lastStr}"
   else
       # 非当天版本 build 号重置
       build = "#{currentTime}.01"
   end
   puts("*************| 更新build #{build} |*************")
   # 更改项目 build 号
   increment_build_number(
       build_number: "#{build}"
   )
end
# 打包成功 jenkins 开始提示上传log
# 使用fastlane上传蒲公英拿不到二维码展示, 所以使用jenkins上传蒲公英
def archiveSuccessLog(outputName,buildConfig)
   # 打好的包 移动到 jenkins的 workspace的目录下,用于jenkins上传蒲公英匹配包内容。永远只保留一份
#   FileUtils.cp_r("#{$ipa_output_directory}" + "/#{outputName}", "#{$ipa_output_upload_directory}" +  "/#{$jenkins_name}.ipa")
   puts" --------------------------------------------------------------------------"
   puts"|                                                                          |"
   puts"|                                                                          |"
   puts"|   🎉🎉🎉 --------->>>>>      #{buildConfig}版本_打包成功     <<<<<-----------🎉🎉🎉  |"
   puts"|                                                                          |"
   puts"|   🎉🎉🎉 --------->>>>>  Jenkins 可以开始上传蒲公英了  <<<<<-----------🎉🎉🎉  |"
   puts"|                                                                          |"
   puts"|                                                                          |"
   puts" --------------------------------------------------------------------------"
end

#
# 所有任务脚本
#
platform :iOS do

 # 
 # *************| 上传到测试版本到蒲公英_测试包 |*************
 #
 desc "上传到测试版本到蒲公英_测试包"
 lane :topgyer_debug do|option|
   puts "*************| 开始打包.ipa文件... |*************"
   # 自动增加build
   updateProjectBuildNumber
   # 自动生成证书
   cert
   # 导出名称
   output_name = "#{scheme_name}_#{version}_#{build}_#{option[:desc]}_#{Time.now.strftime('%Y%m%d%H%M%S')}.ipa"
   gym(
     # 指定输出的ipa名称
       output_name: "#{output_name}",
       # 指定项目的scheme
       scheme: "xxx", 
       # 是否清空以前的编译信息 true:是
       clean: true,
       export_method: "#{ipa_exportMethod}",
       export_options: {iCloudContainerEnvironment: 'Development'},
       # 指定打包方式,Release 或者 Debug 按需修改
       configuration:"Debug",
# 包导出的位置
       output_directory: "#{$ipa_output_directory}",
    )

   # 使用fastlane上传蒲公英拿不到二维码展示, 所以使用jenkins上传蒲公英
   archiveSuccessLog(output_name," Debug ")

       # 这里是 fastlane 直接上传蒲公英
   # 如果需要请打开一下注释,并注释掉archiveSuccessLog(output_name," Debug ")
   # puts "*************| 开始上传__测试版__本到蒲公英... |*************"
   # 配置蒲公英 api_key 和 user_key
   # pgyer(api_key: "你的api_key", user_key: "你的user_key", update_description: "#{option[:desc]}")
   # puts "*************| 上传__测试版__到蒲公英🎉🎉🎉成功🎉🎉🎉 |*************"
 end


  #
  # *************| 上传App Store |*************
  #
  lane :toappstore do
   project_identifier = ""
   puts "*************| 开始上传AppStore... |*************"
   # 自动增加build
   updateProjectBuildNumber
   # 自动生成证书
   # cert
   # 导出名称
   codesigning_identity = "证书名字"
   output_name = "#{scheme_name}_#{version}_#{build}_#{ipa_exportMethod_appStore}_#{Time.now.strftime('%Y%m%d%H%M%S')}.ipa"
   gym(
       # 指定输出的ipa名称
       output_name:output_name,
       # 指定项目的scheme
       scheme:"xxx",
       # 是否清空以前的编译信息 true:是
       clean:true,
       # 指定打包方式,Release 或者 Debug
       configuration:"Release",
       # 指定打包方式,目前支持app-store, package, ad-hoc, enterprise, development
       export_method:"app-store",
       # 上传的环境
       export_options: {iCloudContainerEnvironment: 'Production'},
       # 指定输出文件夹
       output_directory:"#{$ipa_output_directory}",
    )

  deliver(
            # 选择跳过图片和元数据上传,自己去配置
            skip_screenshots:true,
            skip_metadata:true,
            # 上传完成后提交新版本进行审查
            submit_for_review: false,
            force:true,
           )
   puts "*************| 上传AppStore成功🎉 |*************"


   puts "*************| 开始上传__测试版__本到蒲公英... |*************"
   # 配置蒲公英 api_key 和 user_key
   pgyer(api_key: "你的api_key", user_key: "你的user_key", update_description: "#{option[:desc]}")
   puts "*************| 上传__测试版__到蒲公英🎉🎉🎉成功🎉🎉🎉 |*************"
   # 发布testflight测试
   # pilot
  end
end

在自己的项目目录中执行

fastlane topgyer_debug desc:测试

这句话根据自己的lane :topgyer_debug do|option| 修改
成功之后可以看见 , 如果有上传蒲公英给的操作 则会告知蒲公英上传成功,前往蒲公英查看就有新版本了。

17:58:59:  --------------------------------------------------------------------------
17:58:59: |                                                                          |
17:58:59: |                                                                          |
17:58:59: |   🎉🎉🎉 --------->>>>>       Debug 版本_打包成功     <<<<<-----------🎉🎉🎉  |
17:58:59: |                                                                          |
17:58:59: |   🎉🎉🎉 --------->>>>>  Jenkins 可以开始上传蒲公英了  <<<<<-----------🎉🎉🎉  |
17:58:59: |                                                                          |
17:58:59: |                                                                          |
17:58:59:  --------------------------------------------------------------------------

接下来思考的问题是:
不能还是由我们开发人员执行 脚本任务来打包上传蒲公英。
有没有办法能够让测试人员自己去打包呢? 所以接下来我们要做的就是让jenkins执行我们的fastlane脚本,并且自动生成二维码展示。测试人员需要测试包的时候开发人员只需要把代码上传到对应的分支就好了。
我选择了一台专门的机器作为服务器 来做这件事情, 毕竟在自己电脑上多少会有点影响的。

Jenkins

image

Jenkins是一个独立的开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。前身是Hudson是一个可扩展的持续集成引擎。可用于自动化各种任务,如构建,测试和部署软件。Jenkins可以通过本机系统包Docker安装,甚至可以通过安装Java Runtime Environment的任何机器独立运行。

主要用于

持续、自动地构建/测试软件项目,如CruiseControl与DamageControl。
监控一些定时执行的任务。

JAVA JDK

前面我们已经安装了 java JDK 若未安装请前往上方查看安装步骤

Jenkins安装

1.Jenkins官网地址:jenkins-ci.org/ 下载最新的war包双击安装
2.使用brew安装

// 使用brew安装
brew install jenkins‐lts
// 安装完成后启动,直接运行jenkins即可启动服务
//启动jenkins:
brew services start jenkins‐lts

//-------以下命令是可能会使用到的相关命令-----
//重启jekins
brew services restart jenkins‐lts
//更新jekins版本
brew upgrade jenkins‐lts
//停止jenkins
brew stop jenkins‐lts

初始化jenkins
默认访问http://localhost:8080/, 可进入jenkins配置页面。 不要关闭终端否则jenkins会停掉
第一次运行的时候会出现以下界面

jenkins login.png

根据提示的路径去 将密码输入进去 然后点击 Continue
jenkins customize.png

等待推荐的插件安装完成,自己设置账号密码

jenkins配置

在主页(Dashboard)选择 系统管理(manage Jenkins) -->插件管理( Manage Plugins) 去下载插件,本文涉及以下插件

#git参数配置
Git Parameter Plug-In

#构建超时
Build Timeout

#上传蒲公英
Pgyer App Uploda Plugin
//(https://github.com/jenkinsci/pgyer-app-upload-plugin)

#上传蒲公英后 生成二维码展示在jenkins构建列表上
description setter plugin
//(https://plugins.jenkins.io/description-setter)

#构建结果发送邮件通知
Email Extension Plugin
//(https://plugins.jenkins.io/email-ext)

#构建后将构建状态(失败/成功)发送到飞书群
Post build task 
//(https://plugins.jenkins.io/postbuild-task)

#设置打包的名字(好像没有用到)
Build Name and Description Setter
//(https://plugins.jenkins.io/build-name-setter)

创建项目

新建.png

选择: 自由风格的项目
选择项目类型.png

General --> Discard old builds(丢弃旧的构建) 构建的天数的保持最大的个数。
构建天数.png
General --> This project is parameterized(参数化构建过程) --> 添加参数 --> Choice Parameter(添加参数)

这个就是 你在构建的时候可以先择 构建环境和分支,(按需添加!)


参数构建.png
git参数设置
git参数设置.jpeg
名称: BUILD_TYPE
选项: debug
      release
描述: 打包环境
----------------------------------------------
名称: GIT_BRANCH
选项: develop
      master        
描述: 拉取代码的 git分支
源码管理 --> Git

使用Git管理源码 我这里用的是gitlab 的SSH方式管理


git.png
#branch Specifier(指定分支)不要忘记修改为上面设置的选择参数,拉取代码的分支;
*/${GIT_BRANCH}

git管理就是为了让jenkins知道我们的源码在哪里;在第一次构建的时候他会去拉取代码放到.jenkins的workspace中进行管理。

如果你的项目很大,需要的clone时间较长的话,需要设置一下超时时间.
jenkins默认的超时时间是10分钟,根据自己项目设置时间,git clone 太慢解决方案

Additional Behaviours-->高级的克隆行为-->设置超时时间
gitCloneTimeOut.png
构建环境 --> Set build Name 设置打出来的包的展示名字 ,如果没有添加插件 是没有这个选项的
buildName.png
构建 --> 增加构建步骤 --> Execute shell
buildShell.png

shell.png
#脚本命令如下
cd /Users/你的项目目录
fastlane topgyer_debug desc:测试版_Debug

添加完shell命令,保存就可以了

回到首页 --> build with paramters --> 选择环境和分支,开始构建
buildParam.png

startBuild.png

第一次构建需要从Git拉去代码,如果超时了,更改一下,超时时间,上面有介绍;
打包成功了之后发现 每次还是要点击去蒲公英的链接然后才能下载;

经研究了一下怎么直接把蒲公英的链接放在构建完成之后,如下图所示
buildRrcode.png
生成蒲公英二维码

最开始我使用的是 fastlane 上传蒲公英的操作,但是想要拿到二维码不是很容易;
最后想到了直接让 jenkins哪去fastlane打的包然后上传蒲公英就好了,然后成功了!
下面介绍一下操作步骤

1.上传蒲公英

还是进入到我们当前项目的配置里面去 --> 到最后的构建后操作 --> 增加构建后操作步骤


uploadPgy.png

pgyKey.png
pgyer api_key : 你的蒲公英api_key

// 这个位置自己决定就好了,和fastfile文件中的ipa_output_upload_directory地址    是一样就行
Scandir: 打的api包的地址    

file wildcard:  包名字.ipa
注意你需要 吧 fastlane中的fastfile文件中
    ######  这句话的注释打开   #####
    FileUtils.cp_r("#{$ipa_output_directory}" + "/#{outputName}",     "#{$ipa_output_upload_directory}" +  "/#{$jenkins_name}.ipa")
    这个是讲打出来的包拷贝一份到     workspace中,保证ipa文件夹的包只有一个最新的。这个包用于上传蒲公英
2.获取二维码
构建后操作 --> 增加构建后操作步骤 -->Set build description
buildDesc.png
#从上传蒲公英的信息中获取图片
<a href="${appBuildURL}"><img src="${appQRCodeURL}" width="118" height="118"/></a>
3.最后一步

回到首页 --> manager Jenkins(系统管理) --> Configure Globle Security(全局安全配置)


safeHtml.jpeg

标记格式器设置为 Safe HTML

构建结果通知

1.使用python3调用jenkins API查询构建结果发送通知给飞书

添加构建后操作步骤-->Post build Task,然后在Script里面填写命令

#!/bin/bash -il

##python3 发送构建报告到飞书群
echo "py执行前======"

python3 /Users/XXX/.jenkins/自定义py脚本目录/buildResult.py $JOB_URL $JOB_NAME $BUILD_NUMBER

echo "py执行后======"
postbuildTask.jpeg
buildResult.py
#!/usr/bin/env python
#!/usr/bin/python
import sys
import json
import requests
import time


job_url = sys.argv[1]
job_name = sys.argv[2]
BUILD_NUMBER = sys.argv[3]
currenttime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
#job_status = "成功"


url = '自定义飞书机器人webhook地址'
method = 'post'
headers = {
    'Content-Type': 'application/json'
}

print("======================")
print(sys.argv)



def getJson(job_status):
    return {
            "msg_type": "interactive",
            "card": {
                "config": {
                    "wide_screen_mode": True,
                    "enable_forward": True
                },
                "elements": [{
                    "tag": "div",
                    "text": {
                        "content": "项目名称:" + job_name + "\n构建编号:第" + BUILD_NUMBER + "次构建\n" + "构建状态:" + job_status +"\n运行时间:" + currenttime,
                        "tag": "lark_md"
                    }
                }, {
                    "actions": [{
                        "tag": "button",
                        "text": {
                            "content": "查看报告",
                            "tag": "lark_md"
                        },
                        "url": job_url,
                        "type": "default",
                        "value": {}
                    }],
                    "tag": "action"
                }],
                "header": {
                    "title": {
                        "content": job_name + " 构建报告",
                        "tag": "plain_text"
                    }
                }
            }
        }


def jenkins_job_status(job_name):
        try:
                url  ="%slastBuild/api/json" %(job_url)
                print("----------url----------")
                print(url)
                 #Replace 'your_jenkins_endpoint' with your Jenkins URL
#                while True:
                data = requests.get(url).json()
                print(data)
#                if data['building']:
#                        print("----------building----------")
#                        print(url)
#                        #time.sleep(60)
#                else:
                if data['result'] == "FAILURE":
                    print("Job status failed")
                    return  False
                else:
                    print("Job status success ")
                    return True

        except Exception as e:
                print("Job status Exception")
                print(str(e))
                return False




if __name__ =="__main__":

  if jenkins_job_status(job_name):
      print("Put your autmation here for 'job is success' condition")
      print(sys.argv)
      job_status = getJson("成功")
      requests.request(method=method, url=url, headers=headers,json=job_status)

  else:
    print("Put your autmation here for 'job is failed' condition")
    job_status = getJson("失败")
    requests.request(method=method, url=url, headers=headers,json=job_status)



自定义飞书机器人

飞书群-->点击群名称--->群机器人--->添加机器人-->自定义机器人--->填写机器人名称+描述-->添加
不清楚的也可以查看飞书自定义机器人指南,可以参考以上python代码

feishuRobit.jpeg

蒲公英添加飞书webhook地址

具体添加方式可参考蒲公英Webhook设置指南

pgySettingWebhook.jpeg

pgywebhook.jpeg

发送邮件通知

1.构建后操作--->添加构建后的操作步骤--->Editable Email Notification


addEmailBuildNotification.jpeg

2.设置接收人对象为:默认收件人+自定义收件人(构建参数时传入)


WechatIMG129.jpeg

emailSetting.jpeg

3.Advanced Settings ---> Triggers ---> Success / Failure 分别设置对应收件人
successOr.jpeg

4.系统设置-->系统配置-->邮件通知-->参数设置
SMTP服务器/SMTP认证/SMTP端口号 等参数咨询一下公司运维
emailSystemConfig.jpeg

具体可参考jenkins邮件配置和邮件发送

局域网设置

1.修改路径下的plist文件
/usr/local/opt/jenkins/homebrew.mxcl.jenkins.plist
将上面plist中的httpListenAddress后的ip地址,修改为本机IP或者0.0.0.0即可
2..配置文件修改完后,重启Jenkins服务

 brew services restart jenkins‐lts
jenkinsIP.jpeg

结束语

介绍了一下 fastlane 和 Jenkins 的结合使用的过程。比较流水线,如果哪里不对 还望各位指出,然后我们拿到自己电脑的ip http://电脑ip:8080/ 交给测试就好了 要包自己去点构建吧,建议使用网线,这样ip不容易变。
之前也研究过 全部使用Jenkins实现打包上传等过程, 但是jenkins需要配置的东西真的很多,证书、xcode、一系列操作,配置错误就会失败 而且还不容易找出问题,所以选择了fastlane*进行打包上传蒲公英,之后为了获取到二维码直接使用选择了 jenkins上传蒲公英。

常见问题

1.jenkins执行shell脚本时候出现 fastlane Command not found

在安装完fastkane之后执行 fastlane xxx desc:xxx 可以成功打包执行 在jenkins中的shell脚本无法执行出现以下错误

16:20:30 xxx/xxx/xxx/xxx.sh: line 4: fastlane: command not found
16:20:30 Build step 'Execute shell' marked build as failure
16:20:30 New run name is 'iOS_xxx_develop_debug_build(17)'
16:20:30 [UPLOAD TO PGYER] - The build FAILURE, so the file was not uploaded.
16:20:30 [description-setter] Description set: 
16:20:30 Finished: FAILURE

在jenkins的shell脚本命令前添加 #!/bin/bash -ilex 命令eg:

#!/bin/bash -ilex

cd /Users/xxxx/xxxx       # 你的项目地址
fastlane topgyer_debug desc:测试版_Debug

2.使用Python报错

import requests
ModuleNotFoundError: No module named 'requests'

mac下会自动默认使用python2.7,但它没有requests模块,所以会报错,即使你已经安装了python3。
终端输入:

python3 -m pip install requests

3.git 克隆超时(上面有讲到)
Additional Behaviours-->高级的克隆行为-->设置超时时间

4.python3 : command not found
添加环境变量


环境变量.jpeg

整理比较仓促,如有不明白的地方,欢迎赐教!

参考链接:
https://www.jianshu.com/p/4824bf37f9aa/
https://jenkins.io/zh/
https://fastlane.tools/

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

推荐阅读更多精彩内容