CocoaPods 知识

CocoaPods 知识

  • 目录
    • 前言
    • CocoaPods安装
    • CocoaPods原理
    • CocoaPods使用

1、 前言

CocoaPods是OS X和iOS下的一个第三类库管理工具,通过CocoaPods工具我们可以为项目添加被称为“Pods”的依赖库(这些类库必须是CocoaPods本身所支持的),并且可以轻松管理其版本。

相关资料

2、 CocoaPods安装

1、设置 ruby 源

Mac 系统自带的会安装好 ruby 环境

1.1、查看自己电脑的 ruby 源

  • ruby -v
ruby -v
  • 如果自己电脑版本低于这个版本就升级 ruby ,上面显示我的电脑版本不需要升级,可以忽略下面的升级操作
sudo gem update --system
  • 要是没有ruby环境, 执行下面的指令
gem install ruby 

1.2、更换 ruby 镜像

  • ruby 默认的原地址是国外网络地址,通过下面命令查看当前的镜像
gem sources -l

*** CURRENT SOURCES ***

https://rubygems.org/
  • 移除当前镜像
gem sources --remove https://rubygems.org/

https://rubygems.org/ removed from sources
  • 添加国内的 ruby 镜像
gem sources -a https://gems.ruby-china.com/
https://gems.ruby-china.com/ added to sources
  • 再次查看当前镜像,发现已经替换成功
gem sources -l
*** CURRENT SOURCES ***

https://gems.ruby-china.com/

2、安装 CocoaPods

ruby 环境安装后,就可以安装 CocoaPods 了

2.1 检查pod版本

pod --version

2.2 卸载CocoaPods

#卸载
sudo gem uninstall cocoapods 

#卸载指定版本
sudo gem uninstall cocoapods -v 1.9.3

2.3 安装

方法一
#下载最新版本
sudo gem install cocoapods 

#下载指定版本
sudo gem install cocoapods -v 1.9.3

等待了几分钟后,显示下面的信息,便表示已经安装成功了。

方法二
sudo gem install -n /usr/local/bin cocoapods

2.2 检测是否安装成功

  • 可以通过检查pod版本指令查看是否安装成功
pod --version

2.3 下载文件

pod setup

2.4 验证安装成功与否

pod search AFNetworking

3、 CocoaPods原理

核心组件

CocoaPods 是一个 objc 的依赖管理工具,而其本身是利用 ruby 的依赖管理 gem 进行构建的。

CocoaPods是用 Ruby 写的,并由若干个 Ruby 包 (gems) 构成的。在解析整合过程中,最重要的几个 gems 分别是:

  • CocoaPods/Specs
  • CocoaPods/CocoaPods
  • CocoaPods/Core
  • CocoaPods/Xcodeproj

CocoaPods/Specs

这个是一个保存第三方组件 podspec 文件的仓库。第三方组件开发完成之后,会传一份 podspec 文件传到 CocoaPods,这个 Specs 包含了每个第三方组件所有版本的 podspec 文件。当使用某个第三方组件时,如果这些组件支持 CocoaPods,会在 Podfile 中指定 source,例如下面这样:

source 'https://github.com/CocoaPods/Specs.git'

当执行 pod install 或 pod update 等一些命令时,便会从这个仓库找到组件指定版本的 podspec 文件,然后根据这个 podspec 配置信息去获取组件。

CocoaPods/CocoaPod

这是是一个面向用户的组件,每当执行一个 pod 命令时,这个组件都将被激活。该组件包括了所有使用 CocoaPods 涉及到的功能,并且还能通过调用所有其它的 gems 来执行任务。

CocoaPods/Core Core

组件提供支持与 CocoaPods 相关文件的处理,文件主要是 Podfile 和 podspecs。

当执行 pod install等一些命令时。Core组件会解析第三方组件开发者上传的podspec文件和使用者的podfile,以此确定需要为project引入哪些文件。除此之外,当执行与这些文件一些相关的命令时,也由这部分组件处理,例如使用 pod spec lint 来检测 podspec 文件的有效性。

CocoaPods/Xcodeproj

这个 gem 组件负责所有工程文件的整合。它能够对创建并修改 .xcodeproj 和 .xcworkspace 文件。它也可以作为单独的一个 gem 包使用。如果你想要写一个脚本来方便的修改工程文件,那么可以使用这个 gem。

Podfile

Podfile 是一个文件,用于定义项目所需要使用的第三方库。该文件支持高度定制,你可以根据个人喜好对其做出定制。

Podspec

.podspec 也是一个文件,该文件描述了一个库是怎样被添加到工程中的。它支持的功能有:列出源文件、framework、编译选项和某个库所需要的依赖等。

Ruby 概述

方法

  • 简单的方法
    Ruby 代码在调用方法时可以省略括号。
def method_name (var1=value1, var2=value2)
  expr..
end

ruby中的方法以'def'开头,以'end'作为结尾,我们可以为参数设置默认值,如果方法调用时未传递必需的参数则使用默认值,上例中的value1和value2就是默认值。

  • 可变数量的参数
def sample (*test)
  puts "参数个数为 #{test.length}"
  for i in 0...test.length
    puts "参数值为 #{test[I]}"
  end
end
sample "Zara", "6", "F"。

数据类型--Hash

哈希(Hash)是类似 "key" => "value" 这样的键值对集合。哈希类似于一个数组,只不过它的索引(或者叫"键")不局限于使用数字,Hash 的索引几乎可以是任何对象。

Hash 虽然和数组类似,但却有一个很重要的区别:Hash 的元素没有特定的顺序。 如果顺序很重要的话就要使用数组了。

pod 'SwViewCapture', :git=>'git@github.com:startry/SwViewCapture.git', :branch=>'master'
def pod(name = nil, *requirements)
  unless name
    raise StandardError, 'A dependency requires a name.'
  end

  current_target_definition.store_pod(name, *requirements)
end

pod方法后面跟着的参数就是一个Hash的对象,写成key-value的形式就是

{
  ":git": "git@github.com:startry/SwViewCapture.git",
  ":branch": "'master'"
}

block

Ruby中do ~end之间的部分称为块,也可以写为{..}
所以这个target方法可以以这种形式调用:

target('PodSample') {
  pod('SDWebImage', '~> 4.4.2')
}

也可以使用我们常见的形式调用:

target('PodSample') do
  pod('SDWebImage', '~> 4.4.2')
end

eval

这个方法会将字符串当做代码来执行,也就是说 eval 模糊了代码与数据之间的边界,iOS开发过程中也会使用eval执行js代码。

 eval "1 + 2 * 3" => 7

Podfile&Podfile.lock的解析

Podfile

CocoaPods内部定义了一些配置方法,把方法参数转化为内部Hash变量的属性。

Podfile.lock

Podfile.lock文件是用数据描述语言YAML编写的,YAML(YAML Ain’t Markup)是一种简洁的非标记语言,以数据为中心,使用空白,缩进,分行组织数据,从而使得表示更加简洁易读,其可以与json互转,CocoaPods内部是把Podfile.lock文件解析成Hash类型,从而进行参数数据查询和与Podfile文件中的参数进行对比。

4、CocoaPods使用

image.png
  • 远程 pods 库:
    • 可以是CocoaPods 公共库,也可以是一个自定义的 Git 仓库(远程私有库)
  • 本地索引库:
    • 位置可以通过命令$cd ~/.cocoapods/repos进入.公共库和私有库都会在该路径下
  • 源代码库:
    • 可以是CocoaPods公共Git仓库中的库,也可以用任何一个Git, Mercurial或者SVN仓库取代,并且还可以指定具体的commit, branch或者tag。

基础

1. 创建Podfile文件

#进入项目根路径中执行,生成Podfile文件(如果有Podfile文件不用执行pod init)
pod init

说明:Podfile文件详细描述了一个或多个工程中targets的依赖关系

2. Podfile添加第三方库依赖

target 'QSAppDemo' do
  pod 'AFNetworking'
  pod 'YYModel', '~> 1.0.4'
end

3. 下载和安装第三方库

pod install
  • 下载成功后,使用CocoaPods 生成的 .xcworkspace 文件来打开工程;每次更改了 Podfile 文件,要重新执行一次pod update命令;
  • 发生执行pod install或pod update都卡在Analyzing dependencies的情况,是因为要升级CocoaPods的spec仓库,命令后添加--verbose --no-repo-update 参数可以省略此步。

pod指定依赖项版本范围

  • 如果依赖项后不指定版本,默认取最新版本
  pod 'AFNetworking'

版本控制

> 0.1 高于0.1版本(不包含0.1版本)的任意一个版本
>= 0.1 高于0.1版本(包含0.1版本)的任意一个版本
< 0.1 低于0.1版本(不包含0.1版本)的任意一个
<= 0.1低于0.1版本(包含0.1版本)的任意一个
~> 0.1.2 版本 0.1.2的版本到0.2 ,不包括0.2。这个基于你指定的版本号的最后一个部分。这个例子等效于>= 0.1.2并且 <0.2.0,并且始终是你指定范围内的最新版本。

pod制定依赖库的分支或节点

  • 引入master分支(默认)
pod 'AFNetworking', :git => 'https://github.com/AFNetworking/AFNetworking.git'
  • 引入指定的分支
pod 'AFNetworking', :git => 'https://github.com/AFNetworking/AFNetworking.git', :branch => 'develop'
  • 引入某个节点的代码
pod 'AFNetworking', :git => 'https://github.com/AFNetworking/AFNetworking.git', :tag => '2.7.0'
  • 引入某个特殊的提交节点
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '685e31a31bb1ebce3fdb5a752e392dfd8263e169'
  • 使用本地文件

我们也可以指定依赖库的来源地址。如果我们想引入我们本地的一个库,可以这样写:

pod 'AFNetworking', :path => '~/Documents/AFNetworking'

关于Podfile中一些配置说明

Source:

指定pod的来源。如果不指定source,默认是使用CocoaPods官方的source

# 使用官方默认地址(默认)
source 'https://github.com/CocoaPods/Specs.git'

# 公司私有库
source '私有库url'

Target configuration (目标项配置)

platform用于指定应建立的静态库的平台。CocoaPods提供了默认的平台版本配置:

#指定具体平台和版本
platform :ios, '4.0'
platform :iOS

use_frameworks!:

使用此命令会在Pods工程下的Frameworks目录下生成依赖库的framework,如果不使用,会在Pods工程下的Products目录下生成.a的静态库。

target 'Demo' do
  use_frameworks!
end

Dependencies(依赖项)

Podfile指定每个target的依赖项

pod指定特定的依赖库

podspec可以提供一个API来创建podspecs

target通过target指定依赖范围

target

在给定的块内定义pod的target(Xcode工程中的target)和指定依赖的范围。一个target应该与Xcode工程的target有关联。默认情况下,target会包含定义在块外的依赖,除非指定不使用inherit!来继承(说的是嵌套的块里的继承问题)

定义一个Apptarget仅引入AFNetworking库,定义AppTeststarget 引入Nimble的同时也会继承Apptarget里面的AFNetworking库

target 'App' do 
  pod 'AFNetworking' 
  target 'AppTests' do
    inherit! :search_paths 
    pod 'Nimble' 
  end
end
  • target块中嵌套多个子块
target 'ShowsApp' do
    # ShowsApp 仅仅引入ShowsKit
    pod 'ShowsKit' 
    # 引入 ShowsKit 和 ShowTVAuth 
    target 'ShowsTV' do 
        pod 'ShowTVAuth' 
    end 
    # 引入了Specta和Expecta以及ShowsKit
    target 'ShowsTests' do 
        inherit! :search_paths 
        pod 'Specta' 
        pod 'Expecta' 
    end
end
  • 抽象target

定义一个新的抽象目标,它可以方便的用于目标依赖继承。

简单写法

abstract_target 'Networking' do
    pod 'AlamoFire' 
    target 'Networking App 1' 
    target 'Networking App 2'
end

定义一种abstract_target包含多个target

# 注意:这是个抽象的target也就是说在工程中并没有这个target引入ShowsKit
abstract_target 'Shows' do
    pod 'ShowsKit'
    # ShowsiOS target会引入ShowWebAuth库以及继承自Shows的ShowsKit库
    target 'ShowsiOS' do
        pod 'ShowWebAuth'
    end
    # ShowsTV target会引入ShowTVAuth库以及继承自Shows的ShowsKit库
    target 'ShowsTV' do
        pod 'ShowTVAuth'
    end
    # ShowsTests target引入了Specta和Expecta库,并且指明继承Shows,所以也会引入ShowsKit
    target 'ShowsTests' do
        inherit! :search_paths 
        pod 'Specta' 
        pod 'Expecta' 
    end
end

Build configurations(编译配置)

默认情况下, 依赖项会被安装在所有target的build configuration中。为了调试或者处于其他原因,依赖项只能在给定的build configuration中被启用。

下面写法指明只有在Debug和Beta模式下才有启用配置

pod 'MJRefresh', :configurations => ['Debug', 'Beta']

或者,可以弄白名单只指定一个build configurations。

pod 'MJRefresh', :configuration => 'Debug'

注意:默认情况下如果不指定具体生成配置,那么会包含在所有的配置中,如果你想具体指定就必须手动指明。

Subspecs

一般情况我们会通过依赖库的名称来引入,cocoapods会默认安装依赖库的所有内容。

我们也可以指定安装具体依赖库的某个子模块,例如:

# 仅安装QueryKit库下的Attribute模块
pod 'QueryKit/Attribute'
# 仅安装QueryKit下的Attribute和QuerySet模块
pod 'QueryKit', :subspecs => ['Attribute', 'QuerySet']

def

我们还可以通过def命令来声明一个pod集:

def 'CustomPods'
   pod 'IQKeyboardManagerSwift'
end 

然后,我们就可以在需要引入的target处引入:

target 'MyTarget' do 
   CustomPods
end 

这么写的好处是:如果有多个target,而不同target之间并不全包含,那么可以通过这种方式来分开引入。

post_install

当我们安装完成,但是生成的工程还没有写入磁盘之时,我们可以指定要执行的操作。

比如,我们可以在写入磁盘之前,修改一些工程的配置:

post_install do |installer| installer.pods_project.targets.each do |target| 
        target.build_configurations.each do |config| 
            config.build_settings['GCC_ENABLE_OBJC_GC'] = 'supported' 
        end 
    end
end

pre_install

当我们下载完成,但是还没有安装之时,可以使用hook机制通过pre_install指定要做更改,更改完之后进入安装阶段。

pre_install do |installer| 
    # 做一些安装之前的更改
end

abstract! 和 inherit!

  • abstract! 指示当前的target是抽象的,因此不会直接链接Xcode target。

  • inherit! 设置当前target的继承模式。例如:

target 'App' do
   target 'AppTests' do
      inherit! :search_paths 
   end
end

inhibit_all_warnings!

inhibit_all_warnings! 屏蔽所有来自于cocoapods依赖库的警告。你可以全局定义,也能在子target里面定义,也可以指定某一个库:

# 隐藏SSZipArchive的警告而不隐藏ShowTVAuth的警告
pod 'SSZipArchive', :inhibit_warnings => true
pod 'ShowTVAuth', :inhibit_warnings => false

5、CocoaPods创建私有库

CocoaPods拉取开源库的原理:

CocoaPods 有一个开源的索引仓库Specs,仓库存放着所有开源库的各个版本的.podspec文件,.podspec文件包含中记录着源码的地址。首次使用CocoaPods时,会将这个文件库克隆到本地~/.cocoapods/repos/master。

  1. 在Podfile目录下执行 pod install 命令,会从本地的索引库查找该库的.podsepc,如果本地不存在会从远程拉取最新的索引库。
  2. 根据索引库中查到的.podspec文件内容,获取源码地址。
  3. 从源码地址拉取对应版本的代码。

使用是可以发现,首次导入一个开源库时速度较慢,之后再导入时会很快。是因为CocoaPods在本地会有一个缓存目录,存放开源库的源码,首次下载后,再次导入该库时,会直接从本地复制过去。

查看缓存列表使用pod cache list,缓存路径为~/Library/Caches/CocoaPods/Pods/。

创建私有库步骤:

1. 创建podspec文件

1.1 什么是podspec?文件夹打开~/.cocoapods/repos看到
image.png

specs存放的就是cocoapod官网库的specification:说明书,通过这个podspec文件里的信息,找到对应资源URL,然后clone到我们的pod中。可以理解为书的目录,我们查找第三方库的时候实际就是查找这个specs集合。所以我们创建私有库第一步就是创建我们的spec,目录。

先创建空的repository,为了区分命名最好以spec为后缀,说明这是存说明书的库

然后将这个库添加到~/.cocoapods/repos中,操作很简单,终端执行pod命令pod repo add hxkSpec git@github.com:xiaoyiqiu/spec.git

1.2 开始创建私有库podspec,理解为pod私有库说明书

在github上创建一个存放specification的仓库,注意不是存放源码的库,一定不要搞错了

image.png

我建议先创建空的repository,为了区分命名最好以spec为后缀,说明这是存说明书的库

然后将这个库添加到~/.cocoapods/repos中,操作很简单,终端执行pod命令pod repo add TDNIMKitSpec git@github.com:strivever/TDNIMKitSpec.git

命令格式:

pod repo add 【specName】 【spec远程仓库地址】

2.制作我们的pod库

2.1 创建库

pod lib create 【你的pod库名】

2.2 配置.Podspec文件信息

Podspec文件语法

Pod::Spec.new do |s|
  #pod私有库名称
  s.name             = 'TDNIMKit'
  #pod私有库版本号
  s.version          = '0.1.0'
  #pod私有库概要
  s.summary          = 'A short description of TDNIMKit.'

# This description is used to generate tags and improve search results.
#   * Think: What does it do? Why did you write it? What is the focus?
#   * Try to keep it short, snappy and to the point.
#   * Write the description between the DESC delimiters below.
#   * Finally, don't worry about the indent, CocoaPods strips it!

  s.description      = <<-DESC
TODO: Add long description of the pod here.
                       DESC
  #主要,最好能访问
  s.homepage         = 'https://github.com/458362366@qq.com/TDNIMKit'
  # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
  #开源协议
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  #开源作者
  s.author           = 'Striver'
  #源码地址,clone时候就需要使用这个地址跟版本拉取
  s.source           = { :git => 'https://github.com/458362366@qq.com/TDNIMKit.git', :tag =>'0.1.0' }
  #支持的系统版本
  s.ios.deployment_target = '8.0'
  #源码相对路径
  s.source_files = 'TDNIMKit/Classes/**/*'
  
  # s.resource_bundles = {
  #   'TDNIMKit' => ['TDNIMKit/Assets/*.png']
  # }
  # s.public_header_files = 'Pod/Classes/**/*.h'
  #需要使用的框架
  # s.frameworks = 'UIKit', 'MapKit'
  #依赖的其它第三方库
  # s.dependency 'AFNetworking', '~> 2.3'
end

  • cd到源码的文件夹中:
pod lib lint --sources=git@github.com:xiaoyiqiu/spec.git,https://github.com/CocoaPods/Specs.git --allow-warnings
pod repo push spec huang.podspec --sources=git@github.com:xiaoyiqiu/spec.git,https://github.com/CocoaPods/Specs.git --allow-warnings

2.3 验证库有没问题

进行本地验证podspec文件是否正了

cd 到xxx.podspec目录:执行以下指令

pod lib lint --use-libraries --allow-warnings

2.4 编写代码

2.5 上传到gitLab托管平台

  • 上传到远程服务器
  • 一定要打上tag值. 需要跟podspec文件中指定的tag一致
  • 将podsepec中的 source填入仓库地址 上传到仓库记得看一下远程仓库资源是否被同步上去了,不然一会校验会出现资源匹配不到。

2.6 远程仓库验证

  • 方法一(推荐):
pod lib lint --sources=【gitLab ssh地址】,https://github.com/CocoaPods/Specs.git --allow-warnings


pod lib lint --sources=git@github.com:xiaoyiqiu/spec.git(远程库的地址),https://github.com/CocoaPods/Specs.git --allow-warnings
  • 方法二:
pod spec lint --use-libraries --allow-warnings

验证可能很漫长,可以增加 --verbose查看日志

2.6 发布私有库

执行以下发布指令:

  • 方法一:
// pod 命令: 
pod repo push spec huang.podspec 【本地spec文件夹名称】【需要发布的.podspec文件 --sources=【gitLab ssh地址】,https://github.com/CocoaPods/Specs.git --allow-warnings

pod repo push spec huang.podspec --sources=git@github.com:xiaoyiqiu/spec.git,https://github.com/CocoaPods/Specs.git --allow-warnings
  • 方法二:
pod命令 pod repo push 【本地spec文件夹名称】【需要发布的.podspec文件】--use-libraries --allow-warnings --verbose
  • 发布成功后查看一下本地和远程应该都有了podspec

2.7 验证私有仓库是否可用

  • 用pod命令进行搜索,看能否搜索到:$ pod search [私有库名字]
  • 如果搜索不到,在终端执行如下命令rm ~/Library/Caches/CocoaPods/search_index.json或者更新本地仓库 pod repo update然后重新search

2.8 使用私有库

6、常用pod指令

pod setup原理

本质就是将 https://github.com/CocoaPods/Specs 上的项目克隆到/Users/用户名/.cocoapods/repos目录下,若此目录下已经有这个项目,使用pod setup命令则会将项目更新到最新的状态。

pod instal和pod update的区别

  • 执行pod install时,如果Podfile.lock文件存在, 则下载Podfile.lock文件中指定的版本安装,对于不在Podfile.lock文件中的pod库,pod install命令会搜索这个pod库在Podfile文件中指定的版本来安装;

  • 当你想要更新pod库的版本时才使用pod update;它不管Podfile.lock是否存在, 都会读取Podfile文件的的框架信息去下载安装,下载好之后, 再根据下载好的框架信息, 生成Podfile.lock文件

//生成Podfile文件,编写需要的第三方文件
$ pod init 
//安装第三方库,安装成功会生成`podfile.lock`文件用来记录第三方库版本,
后面接上--no--repo--install 的意思是不更新本地索引库
$ pod install 
$ pod install --no--repo--install
//更新第三方库为本地索引库最新版本,后面接上--no--repo--update的意思是不更新本地索引库
$ pod update 
$ pod update --no--repo--update
//搜索当前本地索引仓库中对应的第三方库
$ pod search 第三方库名称
//查看当前版本
$pod --version
//更新本地所有索引库 ,更新指定索引库接上索引库名称即可
$ pod repo update
//通过pod查看已添加的 repo
$ pod repo list

清除相关命令

#查看本地pod缓存
pod cache list

#清除某个库缓存
pod cache clean xxxx

# 清除所有pod缓存
pod cache clean -all

#删除缓存方法
rm ~/Library/Caches/Cocoapods/Pods/Pods/Release

其他

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