GIT的简单介绍

一.GIT的简介

1.什么是git

一款开源的分布式版本控制工具而svn是集中式版本控制器在世界上所有的分布式版本控制工具中,
git是最快、最简单、最流行的,使用的人也是最多的

2.git的起源

作者是Linux之父:Linus Benedict Torvalds,当初开发git仅仅是为了辅助Linux内核的开发(管理源代码)

3.git的现状

在国外已经非常普及,国内并未普及(在慢慢普及)    越来越多的开源项目已经转移到git,git的学习也异常重要

4.git的logo

GIT

二.对于其他版本控制工具的介绍二.对于其他版本控制工具的介绍

1.CVS

最早的开源、免费的集中式版本控制工具
自身设计有问题,会造成提交文件不完整,版本库莫名其妙损坏的情况,当时仅有CVS,所以程序员尽量去避免
这样的问题的出现(文件不完整多提交几次,版本库损坏多备份几份)

2.SVN

修正了CVS的一些稳定性问题,是目前用得最多的集中式版本库控制工具,普及率达到70%-90%

3.ClearCase

收费的集中式版本控制工具,安装比Windows还大,运行比蜗牛还慢
能用ClearCase的一般是世界500强,他们有个共同的特点是财大气粗或者人傻钱多,一般国内没有人用,
一般使用SVN,免费还好用

4.VSS

微软的集中式版本控制工具,集成在Visual Studio中
Visual Studio:开发C#,windowsphone,windows的软件

三.集中式与分布式版本控制器的区别

1.集中式

ComputerA想要服务器最新的代码直接通过checkout向服务器下载
ComputerA在本地修改代码后,直接提交到服务器
ComputerB想要服务器最新的代码直接通过checkout向服务器下载
ComputerB在本地修改代码后,直接提交到服务器
所有的内容统一交给服务器来进行管理

GIT

2.分布式

服务器本地有个代码仓库,从服务器更新代码,上传代码
ComputerA想要服务器最新的代码由本地代码仓库将服务器的代码下载下来,再通过本地代码仓库的项目下载到ComputerA
ComputerA在本地修改完代码后先提交到本地的代码仓库,再由本地的代码仓库提交到服务器
ComputerB操作与ComputerA相似
代码的提交与更新首先会通过本地代码仓库,本地代码仓库再通过服务器,并不是直接交给服务器来进行管理

GIT

四.集中式与分布式的简单对比

1.速度

在很多情况下,git的速度远远比SVN快,git提交可以先提交到本地,网络畅通的时候
再统一提交到服务器,而SVN的改动必须提交到服务器

2.结构

SVN是集中式管理,git是分布式管理(重要)

3.其他

SVN使用分支比较笨拙,需要先从tags中将代码拷贝过来,修改后备份到分支,分支再与主干的项目合并
git可以轻松拥有无限个分支,轻松的在各个分支随意切换
SVN必须联网才能正常工作,git支持本地版本控制工作(git可以先提交到本地版本库)
旧版本的SVN会在每一个目录置放一个.svn(目前svn1.7的只有一个.svn),git只会在根目录拥有一个.git

五.SVN与git的工作流程

1.SVN的工作流程:讲解SVN的时候讲过,这里不再阐述

2.git的工作流程

这幅图以类区分总共有两类角色,一类共享版本库(可以称之为服务器),一类是开发人员
开发人员A想要共享版本库的代码,通过clone命令向服务器下载,将服务器完整的代码下载到本地版本库中,之后本地版本库将代码自动下载到本地
开发人员A在本地修改后,提交代码,通过commit命令先提交到本地版本库,之后通过push命令将本地版本库的代码提交到共享版本库
开发人员B想要共享版本库的代码,通过clone命令向服务器下载,将服务器完整的代码下载到本地版本库中,之后本地版本库将代码自动下载到本地
开发人员B在本地修改后,提交代码,通过commit命令先提交到本地版本库,之后通过push命令将本地版本库的代码提交到共享版本库
开发人员A想要服务器最新的代码,通过pull命令现将服务器最新的代码更新到本地版本库,之后本地版本库将代码自动更新到本地

GIT

3.分布式和集中式的最大区别在于

在分布式下开发者可以本地提交,每个开发者机器上都有一个服务器的数据库

六.如何使用git

1.命令行:常用的命令简单且不多,直接使用命令行就行

2.图形化界面工具

SourceTree GitHub

SourceTree GitHub 3.xcode xcode对git的集成非常非常好,一般情况下,直接使用xcode就行

1.初始化GIT仓库

一.前提准备工作

1.创建一个GIT文件夹代表演示git的所有操作
2.在GIT文件夹下创建命令行的演练,用于演练git的命令行
3.打开终端

二.初始化git仓库

1.进入到命令行的演练文件夹,初始化一个空的代码仓库

  • git init
    GIT

2.给git配置一个用户名和邮箱

git config user.name "XY":配置用户名
git config user.email "XY@163.com":配置邮箱

GIT

3.查看配置的用户名和邮箱

.git->config(使用文本编辑打开)

GIT

4.给git配置全局的用户名和邮箱(只要创建了git就必须配置用户名和邮箱,配置全局的后,当该文件没有用户名和邮箱则会使用全局的)

git config --global user.name"XY":配置全局用户名
git config --global user.email"XY":配置全局邮箱

GIT

5.查看配置的全局的用户名和邮箱

前往->个人->.gitconfif(使用文本编辑打开)

GIT

三.初始化项目

1.在工作目录(.git的同级目录),创建main.m

touch main.m

GIT

2.查看文件状态

git status
  红色:新创建的文件或者修改的文件没有被添加到暂缓区

GIT

3.将main.m添加到暂缓区

git add main.m

GIT

4.查看加入到暂缓区后的文件状态

git status
    绿色:文件在暂缓区,但是没有添加到本地仓库中

GIT

5.将mian.m提交到本地代码仓库中

git commit -m "初始化项目" main.m

GIT

6.查看提交到本地代码仓库后的状态

git status

GIT

7.打开main.m写一些代码

open main.m

GIT

8.查看文件状态(依旧为红色,只要是新建的文件或者是修改的文件都是红色,表示没有被添加到暂缓区)

git status

GIT

9.将mian添加到缓存区

git add main.m

GIT

11.查看添加后的状态(可以进行提交)

git status

GIT

12.将修改的main.m提交到本地代码仓库中

git commit -m "修改了main.m中的内容"

GIT

13.查看提交后的状态

git status

GIT

四.总结

初始化本地的代码仓库之后必须指定用户名和邮箱,否则无法提交
添加文件以及修改文件都要重新 git add 一次,仅仅是在使用命令行进行添加文件的时候才需要,如果是用xcode来创建的文件,xcode会默认执行git add 操作,不需要再进行git add操作

2.GIT工作原理

一.核心的概念

1.工作区(Working Directory):
git的工作目录,.git的同级目录包括同级目录下的子目录,不包括.git

2.版本库(Repository)
    .git目录,用于存储记录版本信息
    1.暂缓区(stage)
    2.分支(master):git会默认自动创建的一个分支,为master分支,可以认为是SVN中的主干
    3.HEAD指针,用于指向当前分支,默认指向master分支,可以通过HEAD指针来回切换分支

二.git add 和git commit 原理

1.git add :将修改的文件或者添加的文件添加到暂缓区
2.git commit:把暂缓区的所有内容提交到当前分支(HEAD指针指向的分支),如果该文件不在暂缓区则不会提交

三.工作原理介绍

1.总步骤
    通过git add 命令将工作区的内容提交到版本库的缓存区
    通过git commit 命令将缓存区的所有内容提交到当前分支

GIT

2.工作区提交到暂缓区

GIT

3.暂缓区提交到当前分支,暂缓区内容清空

GIT

四.总结

1.svn开发工作在主干进行,git开发工作在分支中进行
2.通过add命令可以将工作目录没有被添加到暂缓区的文件添加到暂缓区
3.通过commit命令将暂缓区的所有内容上传到当前分支,提交成功后清空暂缓区内容

3.GIT命令行的其它用法

一.给命令起别名

1."给status"起别名为"st"
    git config alias.st "status"

GIT

2.来到.git->.config查看起的别名

GIT

3.创建person类
    touch person.h person.m

GIT

4.通过刚起的别名"git st"来查看文件状态
    git st

GIT

5.将person类添加到暂缓区
    git add .:.相当于*,将工作目录下所有没有被添加到暂缓区的文件添加到暂缓区

GIT

6.查看添加后的状态
    git st

GIT

7.给"commit -m"起别名为"ci"
    git config alias.ci "commit -m"

GIT

8.来到.git->.config查看起的别名

GIT

9.通过刚起的别名"git ci"将暂缓区的person类提交到本地代码仓库
    git ci "添加了person类":后面不跟文件名,则会将暂缓区内所有的内容提交到本地代码仓库

GIT

10.配置全局的别名
    git config --global alias.st "status"

GIT

11.查看全局的别名(前往->个人->.gitconfig)

GIT

二.git删除文件

1.将person.m删除
    git rm person.m

GIT

2.查看文件状态(在暂存区里面)
    git st

GIT

3.将删除操作提交到本地代码仓库
    git ci "删除了person.m"

GIT

4.查看文件状态
    git st (暂缓区没有任何内容需要提交)

GIT

三.查看版本号

1.第一种查看版本号方式,仅能查看当前版本以及以上的版本
    git log

GIT

2.第二种查看版本号方式,可以查看所有的修改记录(版本绘图)
    git reflog

GIT

3.给查看版本起全局别名
    git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit”

GIT

4.查看起的别名(前往->个人->.gitconfig)

GIT

5.使用别名查看log信息

GIT

四.版本回退

1.打开person.h,添加代码
    open person.h

GIT

2.在没有提交的情况下进行版本回退
    git reset --hard HEAD:强制回退到当前版本,还未提交的一个版本

GIT

3.回退到上一个版本
    git reset --hard HEAD^

GIT

4.回退到上上个版本
    git reset --hard HEAD^^

GIT

5.回退到指定回退到某个版本
    git reset --hard 版本号(至少前5位)

GIT

6.回退到前几个版本
    git reset --hard~1

GIT

五.使用reflog查看日志

git reflog

GIT

六.总结

1.起别名:当前版本库别名,与全局别名(只需要起一次,下次创建仓库后就不用起别名了)
2.删除文件:git rm 文件名,删除后保存在暂缓区,需要提交到代码仓库
3.查看版本号
    git log:查看当期与当前以上的操作
    git reflog:查看版本包含回退的操作
4.版本回退:回退到之前提交过的版本

4.初始化共享版本库和初始化项目

一.作为共享版版本库

1.搭建git服务器
    真实的git服务器的搭建需要使用Linux来进行搭建,搭建难度大且繁琐
2.将代码托管Github:必须开源,不想开源需要交钱
3.或者OSChina:免费,推荐国内速度快
4.一个U盘可以为共享版本库
5.一个文件可以作为共享版本库

二.文件作为共享版本库

1.在GIT目录下创建一个Server的文件夹来作为共享版本库
2.打开终端,使用命令行初始化一个共享版本库
    git init --bare

GIT

3.在GIT目录创建一个开发人员文件夹,并在里面创建一个经理的文件夹代表经理的电脑

三.项目经理初始化项目

1.将服务器完整的内容下载到本地
git clone 服务器地址

GIT

2.添加忽略文件".gitignore",使用git需要忽略的一些文件
touch .gitignore

GIT

4.github中拷贝需要忽略的内容(github搜索.gitignore->找星最多的,点进去,找到object-c,打开复制)

    1.进入github(https://github.com),搜索.gitignore,回车

GIT

2.选择星星最多的项目

GIT

3.找到Object-C点进去

GIT

4.复制所有内容到.gitignore文件中

GIT

5.将.gitignore添加到缓存区
    git add .gitignore

GIT

6.将.gitignore提交到服务器
    git commit -m "添加了需要忽略的文件"

GIT

7.使用xcode的初始化weibo项目放到经理的工作目录中

GIT

8.打开项目weibo项目,所有文件已经在暂缓区了

GIT

9.使用xcode提交到本地版本库(Source control -> commit),提交仅仅是提交到了本地版本库

GIT

10.使用xcode上传到共享版本库(Source control -> push)

GIT

四.张三加入开发(验证项目经理的push操作是否成功在共享版本库中)

开发人员目录下创建张三文件夹,并将共享版本库的代码下载到本地

GIT

五.总结
1.文件作为共享版本库首先要创建个共享版本库,之后将共享版本库下载到本地就有了个.git仓库,在初始化项目之前先创建忽略文件,并从github上复制需要忽略的内容在文件中
2.新增命令,git clone 共享版本库地址:下载共享版本库完整的内容到本地
3.初始化完项目commit提交到本地版本库,push提交到共享版本库

5.GIT共享版本库多人开发

一.多人开发

1.项目经理开发
viewcontroller删除点代码后提交并push到共享版本库(source control -> commit)

GIT

2.张三开发
    1.从共享版本库将最新的代码更新到本地(Source control -> pull)

GIT

2.打印"好好工作"提交并push到共享版本库

GIT

3.项目经理开发
    1.从共享版本库将最新的代码更新到本地(Source control -> pull)
    2.创建person类提交并push到共享版本库

GIT

4.张三开发
    1.从共享版本库将最新的代码更新到本地(Source control -> pull)
    2.打印"张三牛x"提交并push到共享版本库

GIT

5.项目经理开发
    1.在张三打印相同的那行代码打印"张三傻x",commit提交到本地版本库

GIT

2.点击push到共享版本库,报错过期

GIT
GIT

3.点击pull更新代码到本地,发生冲突

GIT

4.解决冲突,两者都保留

GIT

5.提交本地的修改commit并push到共享版本库

GIT

6.张三开发
从共享版本库将最新的代码更新到本地(Source control -> pull)

二.使用静态库

1.将静态库拖入项目中,不识别.h文件也不识别.a文件,可以说不识别RegexLib文件夹的所有内容(仅仅是目前xcode对git支持的bug,以前并没有此情况,期待后期修复)

GIT

2.解决方案(一):
    通过命令行,将RegexLib文件夹的所有内容添加到暂缓区
    git add .

GIT

3.解决方案(二):
    1.先创建真实文件夹拖入到项目中

GIT

2.静态库和代码拖入到项目中

GIT

4.提交添加的静态库并push到共享版本库中

GIT

二.总结

1.使用git先commit提交到本地版本库,再push到共享版本库
2.更新共享版本库的最新代码使用pull
3.先pull后再修改代码可以有效的避免冲突
4.保证只有一个人在修改storyboard的内容
5.在xcode中使用git解决冲突与svn使用解决冲突类似
6.静态库拖入后不识别两种解决方案

6.GIT版本备份

一.多人开发1.0版本

1.经理打印"经理开发1.0版本"代表正在开发1.0版本,之后commit提交并push到共享版本库中(Source Control -> commit)

GIT

2.张三将经理push的代码从共享版本库pull到本地(Source Control -> pull)
3.张三打印"张三完整1.0版本的开发"代表1.0版本已经开发完毕,之后commit提交并push到共享版本库中(Source Control -> commit)

GIT

4.经理将张三push的代码从共享版本库pull到本地(Source Control -> pull)

二.经理对1.0版本进行备份

1.来到经理的weibo工作目录通过终端备份标签名为"weibo1.0",注释为"这个是1.0版本"
    git tag -a weibo1.0 -m "这个是1.0版本" : 给某个版本打上标签

GIT

2.查看标签
    git tag : 查看所有的标签

GIT

3.将打的标签push到服务器
    git push origin weibo1.0 : 将weibo1.0push到默认的代码仓库

GIT

三.多人开发2.0版本

1.经理打印"开始进行2.0版本的开发",代表正在开发2.0版本.之后commit提交并push到共享版本库中(Source Control -> commit)

GIT

2.张三将经理push的代码从共享版本库pull到本地(Source Control -> pull)

四.1.0版本有bug,修复bug

1.经理目录下新建文件夹"weibo1.0fixbug",并将服务器所有的内容clone到本地
    git clone 服务器地址

GIT

2.将当前的代码转为打上标签的代码
    git checkout weibo1.0

GIT

4.创建分支名为weibo1.1fixbug,并切换到这个分支
    git checkout -b weibo1.1fixbug

GIT

5.项目经理写个方法"fixBug"代表修复了1.0的bug,并将修复完bug的版本提交到服务器(Source Control -> Commit)

GIT

6.给修复好的版本打上tag(注意:标签名不能重复,也不能和分支名重复)
    git tag -a weibo1.1 -m "这是修复了1.0版本的1.1版本"

GIT

7.查看所有标签
    git tag

GIT

8.将打上标签的1.1版本push到服务器
    git push origin weibo1.1

GIT

五.将1.1版本合并到正在开发的2.0版本,来到正在开发的2.0项目

1.(Source Control)点击pull,从weibo1.0fixbug里面将代码pull到本地代码仓库

GIT

2.将本地代码仓库的内容push到master分支(Source Control -> push->master)

GIT

3.张三从master分支pull最新的代码(Source Control -> pull->master)

六.删除分支

1.查看所有分支
    git branch -r

GIT

2.删除weibo1.0fixbug分支,需要全路径
    git branch -r -d origin/weibo1.1fixbug

GIT
GIT

3.删除远程的分支
    git push origin --delete 分支名:删除服务器的分支

七.总结

1.开发流程:
    1.开发1.0版本
    2.1.0版本开发完成,对1.0版本打上标签,并将标签push到共享版本库
    3.开始开发2.0版本
    4.突然1.0版本有bug
    5.新建文件夹从共享版本库把所有代码下载到本地
    6.切换到打上标签的代码
    7.创建分支并切换到该分支
    8.在分支中修复bug并提交到共享版本库
    9.将修复完的代码从分支合并到正在开发的2.0版本的分支
    10.继续2.0版本的开发
2.分支和标签名不能重复
    git push origin 分支名 :提交分支到共享版本库

7.新人服务器的搭建

一.创建新人服务器

1.在Server同级目录下创建一个"newWeibo"文件夹,并初始化共享版本库
    git init --bare

GIT

2.打开经理的微博项目,之后配置远程服务器,->Source Control ->master->Configure Server

GIT

3.点击加号添加远程服务器

GIT

4.填写远程服务器的地址与名称

GIT

5.添加后的状态

GIT

6.将weibo项目push到新建的远程服务器

GIT

二.李四获取源代码

开发人员创建李四的文件夹,clone新人服务器的所有东西到李四文件夹
    git clone 新人服务器地址

GIT

三.总结

搭建新人服务器的主要目的是为了保证服务器的代码不会受到新人随意修改

8.创建Github代码仓库和HTTPs验证

一.前提准备

1.在GIT中创建一个Github文件夹演练的github

二.登陆github网站git hub

GIT

三.创建远程仓库

1.点击+ ->New repository

GIT

2.创建远程代码仓库

GIT

3.创建后会来到此界面,将https的url复制下来

GIT

四.在Xcode中添加远程仓库

1.点击Xcode的偏好设置

GIT

2.点击添加仓库

GIT

3.填写服务器地址,源代码管理类型,认证方式以及帐号密码

GIT

4.看到以下界面说明认证成功
GIT

五.初始化项目

1.点击Source Control -> checkout

GIT

2.选择刚刚创建远程仓库

GIT

3.下载到指定位置

GIT

4.查看下载的内容

GIT

5.创建项目放到meituan工作目录

GIT

6.将项目commit并push到远程仓库(Source Control -> commit)

GIT

7.浏览器查看仓库里是否有该项目

GIT

六.开始开发

1.创建dog类commit并push到远程仓库(Source Control -> commit)

GIT

2.浏览器查看仓库里是否有Dog类

GIT

七.总结

1.创建代码仓库的时候选择需要忽略的语言文件
2.在提交到服务器的时候,如果网络不太好,可以先commit,之后再push到远程服务器

9.SSH验证

一.新建一个weChat代码仓库

GIT

二.创建私钥与私钥

1.查看生成步骤
    1.在代码仓库点击个人头像->settings

GIT

2.点击SSH,查看如何生成

GIT

3.点击生成一个新的SSH key

GIT

4.复制命令

GIT

2.生成SSH Key
    1.打开终端,在终端输入刚刚复制的命令,并将邮箱改为github的邮箱帐号,提示文件保存的位置,默认保存在个人目录下,直接敲下回车

GIT

2.提示输入密码,可以不用输入,直接敲回车

GIT

3.确认密码,直接敲回车

GIT

4.当看到以下牛逼的图标时代表SSH key已经生成完了

GIT

3.查看SSH Key
    点击前往->个人->.ssh隐藏文件夹

GIT

三.将公钥放到github上

1.回到 settings界面,点击 New SSH Key

GIT

2.复制公钥并给此公钥起名

GIT

3.查看刚添加的公钥

GIT

四.使用SSH添加远程仓库

1.来到wechat项目,复制SSH Key的地址

GIT

2.在xcode->偏好设置->添加远程仓库

GIT

3.看到这个界面说明已经添加好了

GIT

4.点击Source Control -> Checkout,选择weiChat代码仓库

GIT

5.点击downLoad进行下载

GIT

四.初始化项目

1.创建weChat项目到weChat本地版本库

GIT

2.将代码commit并push到远程代码仓库

GIT

3.浏览器查看远程代码仓库的weChat项目

GIT

4.项目中创建person类之后commit并push到远程代码仓库

GIT

5.浏览器查看刚刚push的person类

GIT

五.github删除代码仓库

1.查看有哪些代码仓库(点击头像,选择profile)

GIT

2.比如删除美团,点击美团项目

GIT

3.点击settings

GIT

4.移到最下面点击Delete this repository

GIT

5.输入要删除的代码仓库全称

GIT

6.再次查看代码仓库,美团已经没有了

GIT

六.总结

1.查询是否存在SSH key
    ls -al ~/.ssh
2.生成SSH key
    ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
3.私钥存在本地用于加密,公钥存在github上用于解密

10.Github的其他用法

一.给MJExtension框架提意见

1.进入到github网站,搜索MJExtension

GIT

2.点击MJExtension

GIT

3.点击Fork到自己的仓库中

GIT

4.以HTTP的验证方式,复制地址

GIT

5.xcode->偏好设置->添加远程仓库

GIT

6.选中添加的远程仓库,点击next

GIT

7.下载到github目录

GIT

8.随意修改点内容提交到远程代码库

GIT

9.github网站查看修改的内容

GIT

10.点击pull requests提交请求

GIT

11.点击create a pull request

GIT

12.在此界面可以查看修改的内容,点击create pull request

GIT

13.填入title与内容点击create pull request就能提交了(建议如果不是很重要的内容,尽量不要去打扰原作者)

GIT

点击pull request查看当前提交的以及作者处理的内容

GIT

点击Issues可以查看对作者提出的问题

GIT

填入标题以及内容点击summit就能提交了

GIT

二.总结

1.如果想给某个框架的作者提意见,可以先将框架fork到自己的仓库中,clone后修改再push到上来,之后向作者提意见
2.如果对框架不明白不会使用的地方可以通过创建Issues向作者提问

11.OSChina的使用

一.进入到OSChina网页登陆/注册账号https://git.oschina.net

GIT

二.创建项目

1.点击创建项目

GIT

2.填写创建项目信息

GIT

3.查看创建好的项目,使用HTTPS认证,复制地址

GIT

4.xcode->偏好设置->添加远程仓库

GIT

5.看到以下界面说明添加成功

GIT

6.点击Source Control -> checkout 选择刚添加的远程仓库

GIT

7.在GIT文件夹创建OSChina文件夹,并将所有东西下载到该文件夹

GIT

8.创建momo项目到momo的文件夹下

GIT

9.commit提交并push到远程仓库

GIT

10.OSChina查看提交的最新的内容

GIT

三.添加其他成员进行合作开发

1.在仓库界面点击管理

GIT

2.点击项目成员管理,点击添加项目成员

GIT

3.添加成员邮箱和权限后点击添加

GIT

四.查看如何添加SSH Key以及权限的含义

1.点击黑色人图标

GIT

2.点击SSH公钥

GIT

3.此处可以填写标题和公钥,点击如何生成

GIT

4.在此界面可以查看如何生成SSH Key以及权限等的含义

GIT
GIT

五.总结

1.OSChina的使用与Github一致,都能使用SSH与Https的认证方式.
2.OSChina可以免费创建私有仓库,而Github私有的需要收费
3.OSChina在国内传输速度快

12.Git添加老项目

一.在github上面添加老项目

1.在github上面添加一个仓库

GIT

2.使用https的认证方式,复制地址

GIT

3.xcode->偏好设置->添加远程仓库

GIT

4.看到如下图说明添加成功

GIT

5.点击checkout,选择test仓库后点击next

GIT

6.下载到github文件夹下

GIT

7.将之前创建好的test项目拖入进来

GIT

8.使用命令行将工作目录所有内容添加到暂缓区
    svn add .

GIT

9.提交项目

GIT

10.github查看已经提交的内容

GIT

二.总结

新项目与老项目使用的区别主要在于:
    创建新项目的时候xcode直接添加到暂缓区中,而老项目只需要使用命令添加一次就可以了

方法一:

使用IJKMediaFramework.framework(将IJKMediaFramework.framework导入到工程,做直播用这个)

  • 添加依赖库

其它依赖库

示例代码(以前项目中用到的地方,捡需要的东西拿)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#import <UIKit/UIKit.h>
@interface PlayViewController : UIViewController
@property (nonatomic, strong)NSURL * liveUrl;
@property (nonatomic, strong)NSString * imageUrl;
@end
#import "PlayViewController.h"
#import "UIImageView+WebCache.h"
#import <IJKMediaFramework/IJKMediaFramework.h>
#define XJScreenH [UIScreen mainScreen].bounds.size.height
#define XJScreenW [UIScreen mainScreen].bounds.size.width
@interface PlayViewController ()
//背景图片
@property (nonatomic, strong)UIImageView *backgroundIamgeView;
//用于播放直播视频的控制器
@property (atomic, retain) id <IJKMediaPlayback> player;
@end
@implementation PlayViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
//直播试图
[self goPlaying];
// 开启通知
[self installMovieNotificationObservers];
[self loadUI];
}
- (void)goPlaying{
self.player = [[IJKFFMoviePlayerController alloc]initWithContentURL:self.liveUrl withOptions:nil];
//获取到直播试图
UIView *playerView = [self.player view];
playerView.frame = self.view.bounds;
[self.view addSubview:playerView];
//这一步必须有,否则不能播放,准备完毕自动开始播放
[self.player prepareToPlay];
}
- (void)loadUI
{
//背景图片
self.backgroundIamgeView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[self.backgroundIamgeView sd_setImageWithURL:[NSURL URLWithString: _imageUrl] placeholderImage:[UIImage imageNamed:@"LaunchImage-700"]];
[self.view addSubview:self.backgroundIamgeView];
//背景图片的毛玻璃效果
UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
visualEffectView.frame = self.backgroundIamgeView.bounds;
[self.backgroundIamgeView addSubview:visualEffectView];
// 返回
UIButton * backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
backBtn.frame = CGRectMake(10, 24, 33, 33);
[backBtn setImage:[UIImage imageNamed:@"show_image_back_icon"] forState:UIControlStateNormal];
[backBtn addTarget:self action:@selector(goBack) forControlEvents:UIControlEventTouchUpInside];
backBtn.layer.shadowColor = [UIColor blackColor].CGColor;
backBtn.layer.shadowOffset = CGSizeMake(0, 0);
backBtn.layer.shadowOpacity = 0.5;
backBtn.layer.shadowRadius = 1;
[self.view addSubview:backBtn];
// 暂停
UIButton * playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
playBtn.frame = CGRectMake(XJScreenW - 43, 24, 33, 33);
[playBtn setImage:[UIImage imageNamed:@"playButtonPause"] forState:(UIControlStateNormal)];
[playBtn setImage:[UIImage imageNamed:@"playButtonPlay"] forState:(UIControlStateSelected)];
[playBtn addTarget:self action:@selector(play_btn:) forControlEvents:(UIControlEventTouchUpInside)];
playBtn.layer.shadowColor = [UIColor blackColor].CGColor;
playBtn.layer.shadowOffset = CGSizeMake(0, 0);
playBtn.layer.shadowOpacity = 0.5;
playBtn.layer.shadowRadius = 1;
[self.view addSubview:playBtn];
}
// 返回
- (void)goBack
{
//停播
[self.player shutdown];
[self dismissViewControllerAnimated:YES completion:nil];
}
// 暂停开始
- (void)play_btn:(UIButton *)sender {
sender.selected = !sender.selected;
if (![self.player isPlaying]) {
// 播放
[self.player play];
}else{
// 暂停
[self.player pause];
}
}
/*
IJKMPMoviePlayerLoadStateDidChangeNotification
IJKMPMoviePlayerPlaybackDidFinishNotification
IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
IJKMPMoviePlayerPlaybackStateDidChangeNotification
*/
#pragma mark 通知
- (void)installMovieNotificationObservers{
//监听播放状态,当播放状态改变时将北京图片设为透明
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayBackStateDidChange:) name:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:_player];
}
- (void)removeMovieNotificationObservers {
[[NSNotificationCenter defaultCenter] removeObserver:self name:IJKMPMoviePlayerPlaybackStateDidChangeNotification object:_player];
}
- (void)moviePlayBackStateDidChange:(NSNotification*)notification {
self.backgroundIamgeView.hidden = YES;
}
- (void)dealloc{
[self removeMovieNotificationObservers];
}
@end

方法二:

使用第三方(KRVideoPlayer)

github链接

pod “KRVideoPlayer”

1
2
3
target 'xxxxx' do
pod "KRVideoPlayer"
end

示例代码(以前项目中用到的地方,捡需要的东西拿,看不懂请点击右上角)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#import "XYTopicVideoView.h"
#import <UIImageView+WebCache.h>
#import "XYTopicModel.h"
#import "XYSeeBigPictureController.h"
#import <KRVideoPlayerController.h>
@interface XYTopicVideoView ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIImageView *placeholderView;
@property (weak, nonatomic) IBOutlet UILabel *playcountLabel;
@property (weak, nonatomic) IBOutlet UILabel *videotimeLabel;
@property (nonatomic, strong) KRVideoPlayerController *videoController;
@end
@implementation XYTopicVideoView
- (void)awakeFromNib
{
self.autoresizingMask = UIViewAutoresizingNone;
// 允许图片交互
self.imageView.userInteractionEnabled = YES;
// 给图片添加点击手势
[self.imageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(seeBigPicture)]];
}
- (void)seeBigPicture
{
XYSeeBigPictureController *seeBigPicture = [[XYSeeBigPictureController alloc] init];
seeBigPicture.topic = self.topic;
[self.window.rootViewController presentViewController:seeBigPicture animated:YES completion:nil];
}
- (void)setTopic:(XYTopicModel *)topic
{
_topic = topic;
// 显示占位图
self.placeholderView.hidden = NO;
[self.imageView sd_setImageWithURL:[NSURL URLWithString:topic.image1] placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (!image) return; // 图片下载不成功
// 隐藏占位图
self.placeholderView.hidden = YES;
}];
}
- (IBAction)play {
NSURL *videoURL = [NSURL URLWithString:self.topic.videouri];
[self playVideoWithURL:videoURL];
}
- (void)playVideoWithURL:(NSURL *)url
{
if (!self.videoController) {
self.videoController = [[KRVideoPlayerController alloc] initWithFrame:[UIScreen mainScreen].bounds];
__weak typeof(self)weakSelf = self;
[self.videoController setDimissCompleteBlock:^{
weakSelf.videoController = nil;
}];
[self.videoController showInWindow];
}
self.videoController.contentURL = url;
}
- (void)layoutSubviews
{
[super layoutSubviews];
self.videoController.frame = self.imageView.frame;
}

1. 什么是真机调试?

简单理解就是将App项目运行到真机上进行测试

2.为什么要运行到真机上, 不是可以运行到模拟器上吗?(APP发布之前一定要做真机调试!!!)

真机和模拟器环境的差异
    内存环境,网络环境; 
    传感器: 磁力计,陀螺仪,距离传感器等;
    特定功能:拍照, 打电话,发短信,蓝牙等。
    用户体验不一样

3. 怎样做真机调试?

Xcode7.0之前,并不是任何人,任何电脑,任何APP,任何真机设备都可以进行真机调试的

1. 限制人

     必须拥有Apple ID([https://appleid.apple.com])
     加入开发者计划,升级为**开发者账号**([https://developer.apple.com])
 2. 限制电脑

     配置与电脑关联的cer证书
         需要使用需要真机调试的电脑,生成CSR文件
         CSR文件: 证书签名请求文件
   3. 限制App

    配置需要真机测试App的BundleID
         区分不同APP,就是通过App的唯一标识: BundleID
 4. 限制真机设备

     配置需要真机测试的真机UDID
         苹果每台真机设备都拥有一个唯一标识:UDID

Xcode7.0之后, 做真机调试, 非常简单 只需要拥有Apple ID即可, 不需要以上限制

4. 真机调试注意事项

1.以上步骤完成后,你会有两个文件:cer文件,MobileProvision文件,只需要双击安装即可.

cer证书被添加到钥匙串中
描述文件被安装到Xcode中
    资源库 -> MobileDevice -> Provisioning Profiles

2.必须保证cer证书和描述文件一致

Xcode -> targets -> build setting -> code signing

3.创建一个APP,并确认BundleID与配置一致

如果不一致, 修改XCode项目的BundleID, 与配置一致.

4.真机运行时, 如果发现真机设备无法选中, 查看项目最低部署版本是否过高, 大于真机设备的系统版本

如果真机设备系统版本过高, 则无法选中真机进行运行

5. 备注补充

开发者账号分类

个人账号(99$)==688

功能:可以真机调试, 打包测试, 程序发布. 
优点:申请速度快, 给钱就行, 1-3个工作日即可 
缺点:
    1.iTunes查看到的是个人信息, 无法间接为公司做宣传 
    2.无法创建管理自己的开发团队

公司账号(99$)

功能:可以真机调试, 打包测试, 程序发布. 
优点:
    1.iTunes可以查看企业信息, 间接为公司做宣传 
    2.可以创建和管理自己的开发团队
缺点:
    1.申请复杂,需要”邓白氏”认证
    2.申请周期比较长(连同”邓白氏编码”申请, 最好准备30天左右时间)

企业账号(299$)

功能:可以真机调试, 打包测试
优点:
    1.可以在企业内部随意安装到苹果设备,不需要经过AppStore审核
    2.可以创建和管理自己的开发团队
    3.版本更新迭代比较快, 不需要经过审核
缺点:
    1.申请复杂,需要”邓白氏”认证
    2.申请周期比较长(连同”邓白氏编码”申请, 最好准备30天左右时间)
    3.不能使用此证书,将App发布到AppStore

6. 开发经验

1.尽量不要从网络渠道以及代申请的公司去申请”邓白氏编码”.

花钱多, 而且申请下来的”邓白氏编码”不一定和苹果服务器数据库内一致, 最终不可用; 浪费时间和金钱
最正确的做法: 直接和苹果客服MM联系, 她们会告诉你申请流程, 需要提交哪些材料
客服电话: 400 670 1855

2.企业级账号使用场景

App是针对某一特定人群制定使用.只在企业内部安装, 无需发布到AppStore供他人下载

3.真机调试证书只能生成两个!!

也就意味着,只能绑定两台电脑进行真机调试
注意:如果别人已经配置了两个,而且正在使用,不能随便把别人的证书删除;
解决方案:
    此时只能使用从已经配置证书的电脑中,导出P12文件,进行共享;
    作   用: 让其他电脑设备不需要生成cer证书,也可以进行真机调试;

步骤图解

image

image

4.测试的真机设备UDID最多只能添加100次, 而不是100台

也就是说, 如果你加够了100次之后, 即使删除之前的设备名额, 也无法继续添加
苹果会在下一年, 给你一次删除设备的机会, 你可以删除一些设备, 来恢复一些名额.
但是, 一旦你添加了设备后, 苹果则视为你自动放弃添加设备!!

步骤图解

image
image
image
image
image

5.真机调试最终需要的文件

cer文件(或者p12文件)
MobileProvision文件

6.XCode7真机调试

只需要AppID,在Xcode7 -> preference -> Account 中添加即可
然后直接真机调试时,会弹出一个框,提示缺少描述文件. 直接点击”Fix issue”选项,Xcode会自动请求苹果服务器生成对应的描述文件

==============

二. 打包测试

1. 什么是打包测试?

就是指将项目打包成为.ipa的压缩包, 供指定设备安装测试.

2. 为什么要做打包测试?

当进入到测试阶段, 需要专门的测试人员对APP进行测试, 此时需要将APP安装到测试人员的测试设备上, 此时最佳的方案, 就是直接将项目打包成为.ipa包, 供测试人员下载测试;

3. 怎样进行打包测试?

1.限制人

必须拥有Apple ID([https://appleid.apple.com])
加入开发者计划,升级为**开发者账号**([https://developer.apple.com])

2.限制电脑

重新配置一个**打包测试**证书(Ad Hoc)
需要使用需要打包测试的电脑,生成CSR文件
    CSR文件: 证书签名请求文件

3.限制App

配置需要真机测试App的BundleID
    区分不同APP,就是通过App的唯一标识: BundleID

4.限制真机设备

配置需要真机测试的真机UDID
    苹果每台真机设备都拥有一个唯一标识:UDID

5.根据2,3,4重新生成打包测试描述文件

6.分别安装cer证书和对应的描述文件

7.运行设备选择真机后 选择Product -> Archive

===================

三. 程序发布

1. 什么是程序发布?

就是指将APP发布到AppStore, 供指定区域用户下载

2. 为什么要程序发布?

赚钱.

3. 程序发布的步骤?

1.限制人

必须拥有Apple ID([https://appleid.apple.com])
加入开发者计划,升级为**开发者账号**([https://developer.apple.com])

2.限制电脑

重新配置一个**发布**证书
需要使用需要程序发布的电脑,生成CSR文件
    CSR文件: 证书签名请求文件

3.限制App

配置需要真机测试App的BundleID
    区分不同APP,就是通过App的唯一标识: BundleID

4.根据2,3重新生成发布描述文件

** 注意: 程序发布, 是发布到AppStore, 所以不会有限制设备一项**

5.在开发中心新建App, 并填写App相关的信息

就比如我们下载别人的app,就会发现里面有预览图片, app版本,以及功能简介等信息, 那这些信息都是我们在这一步填写的

6.写好一个应用程序

注意:必须要有程序图标,启动图片等,否则上传会失败

7.运行设备选择真机后 选择Product -> Archive

8.选择 submit 打包项目,上传构建版本

9.提交审核

=========================

4. 经验补充

1.常规审核周期

审核周期2至20天不等, 而且他们碰到节假日还放假.

2.加急审核

概念: 简单理解就是你联系苹果审核人员,跟他们说明理由,让他们优先给你们审核
地址: [https://developer.apple.com/contact/app-store/?topic=expedite]

3.加急审核注意事项(亲身体验)

加急审核,审核更加严格,亲身体验
首次发布,一般加急审核不给审批
加急审核申请一定要理由足够强大(一般是上线后发现重大Bug)
加急审核好爽, 只要你申请加急审核通过了. 那么只要你的app没有上架,就会一直处于加急审核状态, 一直到你上架为止, 此次加急才算    结束(曾经有连续被拒7次经验,历时才10天)
    加急审核有次数限制(一年好像有3次, 我只用过一次,没测试过)

==========================

四. 内购和广告

1. 什么是内购?

内购就是指,在APP内购买某些产品
如果你在App中销售的商品,跟App有关(例如植物大战僵尸中的道具,需要开启关卡,拥有某种技能等等).那么,苹果规定,必须通过内购方式购买.
内购分成: 3 : 7

2. 为什么做内购?

开发者创收的一种模式: free + 内购
某些业务必须使用内购

3. 内购的产品类型?

1.非消耗品(Nonconsumable)

买了就一直有,不会消耗,例如开启关卡
一般指的是在游戏中一次性购买并拥有永久访问权的物品或服务。非消耗品物品可以被用户再次下载,并且能够在用户的所有设备上使用

2.消耗品(Consumable)

买了就用,用了就没
专为支持可消耗的物品或服务设计的,消耗品购买不可被再次下载,根据其特点,消耗品不能在用户的设备之间跨设备使用,除非自定义服务在用户的账号之间共享这些信息

3.其他类型

以下三种类别在iBooks中使用,目前iBooks不支持大陆市场
    免费订阅(Free subscriptions)
    自动续费订阅(Auto-renewing subscriptions)
    非自动续费订阅(Nonrenewing subscriptions)

4.内购的流程

类似于商场购物流程, 参照下图
image

5.内购演练

在App管理中心,创建一个App,并填写App信息
    注意: 此处创建的App时,填写套装ID,时,必须选择可以内购的套装ID

创建内购商品,并添加到App,指定此App,可以销售哪些商品
    注意: 创建内购商品的前提,是你已经填写了税务/银行信息,否则的话,无法创建

添加用于测试内购的测试账号

创建App项目,开始开发
代码实现内购流程
  • (1) 从APP服务器请求数据列表, 并行苹果服务器请求可以销售的商品列表

    [XMGDataTool getGoodsWithResult:^(NSArray *goods) {
        NSArray *ids = [goods valueForKeyPath:@"goodID"];
        // 请求哪些商品可以卖
        NSSet *idSet = [NSSet setWithArray:ids];
        SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:idSet];
        request.delegate = self;
        [request start];
    }];
    
  • (2) 在代理方法中获取并显示可销售列表

    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
    {
        self.products = response.products;
    }
    
  • (3) 用户购买商品, 并监听商品交易状态

    // 取出商品
    SKProduct *product = self.products[indexPath.row];
    
    // 购买商品
    SKPayment *payMent = [SKPayment paymentWithProduct:product];
    
    // 把凭证加入到队列, 等待用户付款
    [[SKPaymentQueue defaultQueue] addPayment:payMent];
    
    // 设置监听者, 监听整个交易状态
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    
  • (4) 实现监听交易状态方法

     // 交易状态发生变化时调用
    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
    {
    
    [transactions enumerateObjectsUsingBlock:^(SKPaymentTransaction * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) 
    {
    
        //  SKPayment *payment , 小票 , 包含商品
        //  SKPaymentTransactionState transactionState 交易状态
    switch (obj.transactionState) {
        case  SKPaymentTransactionStatePurchasing:
            NSLog(@"正在付款");
        break;
    
        case  SKPaymentTransactionStatePurchased:
            {
                NSLog(@"付款结束");
                [queue finishTransaction:obj];
                break;
            }
        case  SKPaymentTransactionStateFailed:
            {
                   NSLog(@"交易失败");
                [queue finishTransaction:obj];
                break;
            }
        case  SKPaymentTransactionStateRestored:
            NSLog(@"恢复购买");
            break;
        case SKPaymentTransactionStateDeferred:
               NSLog(@"推迟付款");
            break;
    
        default:
            break;
        }
          }];
     }
    

4. 广告

广告的作用?
    属于创收的一种方式, 你在App内展示广告,苹果会付费给你,分成从原来的4:6 到 3:7

如何展示广告
    导入框架: iAd.framework
    添加控件: ADBannerView 
    实现代理 ADBannerViewDelegate,优化用户体验

1. 配置证书/描述文件/安装:

1. 确定哪台电脑可以进行App发布

1. 确定哪台电脑可以进行App发布

2. 确定哪个App可以进行发布

2. 确定哪个App可以进行发布

3. 根据证书+APP ID 生成描述文件

3. 根据证书+APP ID 生成描述文件

2. 在开发中心创建APP:

1.登录iTunes

1.登录iTunes

2.选择”我的APP”模块

2.选择"我的APP"模块

3.新建APP

3.新建APP

4.填写APP基本信息

4.填写APP基本信息

5.填写APP其他信息

5.填写APP其他信息

6.指定APP销售价格

6.指定APP销售价格

3. 打包上传:

1

1

2

2

3

3

4

4

5

5

6

6

7

7

8

8

9

9

1.证书生成/描述文件的配置/证书安装

#图:

1. 重新生成打包测试证书(确定哪台机器可以进行打包测试)

1.重新生成打包测试证书(确定哪台机器可以进行打包测试).png)

2. 确定哪个APP可以进行打包测试

2. 确定哪个APP可以进行打包测试

3. 确定哪些设备可以安装APP测试包

3. 确定哪些设备可以安装APP测试包

4. 根据前三项生成描述文件

4. 根据前三项生成描述文件

2.打包测试

5.0 开始打包测试-项目BundleID

5.0 开始打包测试-项目BundleID

5.1 开始打包测试-检查工作证书和描述文件

5.1 开始打包测试-检查工作证书和描述文件

6. 开始打包测试

6. 开始打包测试

7. 打包成功,导出

7. 打包成功,导出

8. 打包成功,选择导出方法

8. 打包成功,选择导出方法

9. 选择开发团队,用作描述

9. 选择开发团队,用作描述

10. 选择APP设备支持

10. 选择APP设备支持

11. 打包概述

11. 打包概述

#文字:

测试打包

  • 1.登录apple的开发者主页:developer.apple.com

  • 2.选择Ad Hoc生成一个ios_distribution.cer: 让电脑具备打包程序的能力

  • 3.新建一个App ID : 确定哪个APP可以被打包测试

  • 4.利用用户设备的UDID注册设备(确定哪些设备可以被打包测试)

  • 5.选择Ad Hoc利用ios_distribution.cer + 设备UDID + App ID –> 描述文件
    (描述文件的作用:

    • 1> 能知道在哪台电脑上, 为哪台设备打包哪个程序
    • 2> 哪台设备需要测试哪个程序)
  • 6.最终产生了3个文件

    • 1> CertificateSigningRequest.certSigningRequest

      • 包含了电脑的信息
      • 发送给苹果服务器, 苹果服务器根据文件信息来生成一个电脑证书
      • 生成的证书就可以让对应的电脑具备某个特殊的能力
    • 2> ios_distribution.cer

      • 打包证书
      • 安装这个证书后, 电脑就具备打包程序的能力
    • 3> nj_iphone6_news.mobileprovision

      • 里面包含了3个信息:ios_distribution.cer + 设备UDID + App ID
  • 7.安装证书和描述文件

    • 1> ios_distribution.cer
    • 2> nj_iphone6_news.mobileprovision
  • 8.项目Scheme右边的设备选择iOS Device

  • 9.点击Xcode的菜单

    • Product –> Archive –> Distribute –> ….Ad Hoc… –> 选择对应的描述文件
  • 10.生成一个ipa文件,发给测试人员和客户

    • ipa本质是zip
    • android的安装包是APK格式,本质也是zip

真机调试步骤:

1.Xcode7.0下载

1.Xcode7.0下载

2.进入Xcode偏好设置

2.进入Xcode偏好设置

3.添加AppID

3.添加AppID

4.调整部署版本

4.调整部署版本

5.运行报错提示

5.运行报错提示

6.Xcode自动解决问题

6.Xcode自动解决问题

7.成功生成

7.成功生成

常见问题以及解决方案

1. The account XXX has no team with ID XXXX

问题描述

解决方法:

登录开发者支持网址
进入苹果开发者技术支持
填写联系信息
发送信息
收到的邮件回复-等待结果
收到邮件-问题解决

2. An App ID with identifier XXX is not avaliable. Please enter a different string

问题描述

解决方法:

解决方案

3. Could not launch XXX

问题描述

解决方法:

进入手机设置
进入手机通用
点击信任设备
信任设备
信任后结果

左滑执行pop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#import <UIKit/UIKit.h>
@interface XYNavigationController : UINavigationController
@end
#import "XYNavigationController.h"
@interface XYNavigationController ()<UIGestureRecognizerDelegate>
@end
@implementation XYNavigationController
// 设置navbar的属性
+ (void)load
{
UINavigationBar *navBar = [UINavigationBar appearanceWhenContainedIn:self, nil];
// 正常
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
attrs[NSFontAttributeName] = [UIFont boldSystemFontOfSize:20];
[navBar setTitleTextAttributes:attrs];
// 背景图片
[navBar setBackgroundImage:[UIImage imageNamed:@"navigationbarBackgroundWhite"] forBarMetrics:UIBarMetricsDefault];
}
- (void)viewDidLoad {
[super viewDidLoad];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self.interactivePopGestureRecognizer.delegate action:@selector(handleNavigationTransition:)];
pan.delegate = self;
[self.view addGestureRecognizer:pan];
self.interactivePopGestureRecognizer.enabled = NO;
// XYLog(@"%@",self.interactivePopGestureRecognizer);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (self.childViewControllers.count > 0) {
// 隐藏底部工具栏
viewController.hidesBottomBarWhenPushed = YES;
viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"navigationButtonReturn"] heghImage:[UIImage imageNamed:@"navigationButtonReturnClick"] target:self action:@selector(back) title:@"返回"];
}
[super pushViewController:viewController animated:animated];
}
- (void)back
{
[self popViewControllerAnimated:YES];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return self.childViewControllers.count > 1;
}
@end

图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#import <UIKit/UIKit.h>
@interface XYTabBar : UITabBar
@end
#import "XYTabBar.h"
@interface XYTabBar ()
@property (nonatomic, weak) UIButton *pulsButton;
@property (nonatomic, strong) UIControl *previousClickedTabbatButton;
@end
@implementation XYTabBar
- (UIButton *)pulsButton
{
if (_pulsButton == nil) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:@"tabBar_publish_icon"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"tabBar_publish_click_icon"] forState:UIControlStateHighlighted];
[button sizeToFit];
[self addSubview:button];
_pulsButton = button;
}
return _pulsButton;
}
- (void)layoutSubviews
{
[super layoutSubviews];
NSInteger count = self.items.count + 1;
CGFloat w = self.xy_width / count;
CGFloat h = self.xy_height;
CGFloat x = 0;
int i = 0;
for (UIControl *tabBarButton in self.subviews) {
if (i == 0) {
self.previousClickedTabbatButton = tabBarButton;
}
if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
if (i == 2) {
i += 1;
}
x = i * w;
tabBarButton.frame = CGRectMake(x, 0, w, h);
i ++;
// 添加监听
[tabBarButton addTarget:self action:@selector(tabBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
}
}
// 发布按钮的位置
self.pulsButton.center = CGPointMake(self.xy_width * 0.5, self.xy_height * 0.5);
}
#pragma mark - 监听
/**
* 监听重复点击
*/
- (void)tabBarButtonClick:(UIControl *)tabBarButton
{
if (self.previousClickedTabbatButton == tabBarButton) {
[[NSNotificationCenter defaultCenter] postNotificationName:XYTabBarButtonDidClickRepeatNotification object:nil];
}
self.previousClickedTabbatButton = tabBarButton;
}
@end

图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#import <UIKit/UIKit.h>
@interface XYTabBarController : UITabBarController
@end
#import "XYTabBarController.h"
#import "XYEssesionViewController.h"
#import "XYNewViewController.h"
#import "XYFriendTrendsViewController.h"
#import "XYMeTableViewController.h"
#import "XYNavigationController.h"
#import "XYTabBar.h"
@interface XYTabBarController ()
@end
@implementation XYTabBarController
// 设置tabbarItem的相关属性
+ (void)load
{
UITabBarItem *tabBarItem = [UITabBarItem appearanceWhenContainedIn:self, nil];
// 正常
NSMutableDictionary *norAttres = [NSMutableDictionary dictionary];
norAttres[NSFontAttributeName] = [UIFont boldSystemFontOfSize:13];
[tabBarItem setTitleTextAttributes:norAttres forState:UIControlStateNormal];
// 选中
NSMutableDictionary *selAttres = [NSMutableDictionary dictionary];
selAttres[NSForegroundColorAttributeName] = [UIColor blackColor];
[tabBarItem setTitleTextAttributes:selAttres forState:UIControlStateSelected];
}
- (void)viewDidLoad {
[super viewDidLoad];
// 添加所有控制器
[self setupAllChildVc];
// 自定义tabbar
XYTabBar *tabBar = [[XYTabBar alloc] init];
[self setValue:tabBar forKeyPath:@"tabBar"];
}
- (void)setupAllChildVc
{
//精华
[self setupOneChildVc:[[XYEssesionViewController alloc] init] image:@"tabBar_essence_icon" selImage:@"tabBar_essence_click_icon" title:@"精华"];
//新帖
[self setupOneChildVc:[[XYNewViewController alloc] init] image:@"tabBar_new_icon" selImage:@"tabBar_new_click_icon" title:@"新帖"];
//关注
[self setupOneChildVc:[[XYFriendTrendsViewController alloc] init] image:@"tabBar_friendTrends_icon" selImage:@"tabBar_friendTrends_click_icon" title:@"关注"];
//我
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:NSStringFromClass([XYMeTableViewController class]) bundle:nil];
[self setupOneChildVc:[storyboard instantiateInitialViewController] image:@"tabBar_me_icon" selImage:@"tabBar_me_click_icon" title:@"我"];
}
- (void)setupOneChildVc:(UIViewController *)vc image:(NSString *)image selImage:(NSString *)selImage title:(NSString *)title
{
vc.tabBarItem.title = title;
vc.tabBarItem.image = [UIImage imageNamed:image];
vc.tabBarItem.selectedImage = [UIImage imageNamed:selImage];
XYNavigationController *nav = [[XYNavigationController alloc] initWithRootViewController:vc];
[self addChildViewController:nav];
}

图片