文档说明
- 在APP开发过程中要严格遵守本文档制定的开发规范,如果特定开发平台的开发规范和通用开发规范出现冲突,以特定平台的开发规范为准。
- 除非特殊说明,驼峰式指小驼峰式,即第一个单词的字母小写,其余单词的首字母大写,其余字母小写,单词之间不以空格断开或连接号(-)、下划线(_)连接的写法,如:lowerCamelCase
- 除非特殊说明,大驼峰式(也叫帕斯卡式)指第一个单词前缀字母使用大写字母;后续单词的首字母亦用大写字母,单词之间不以空格断开或连接号(-)、下划线(_)连接的写法,如:UpperCamelCase、PascalCase
- 除非特殊说明,小写下划线式指全部字母小写,单词之间使用下划线(_)连接的写法,如:lower_underscore_case
- 除非特殊说明,大写下划线式指全部字母大写,单词之间使用下划线连接的写法,如:UPPER_UNDERSCORE_CASE
- 有可能进行修改或者增加
通用(Android、iOS)开发规范
文件相关规范
- 文件编码统一使用UTF-8
编码相关规范
- 不要忽略异常处理
- 缩进使用4个空格
- 变量命名使用驼峰式
- 方法命名使用和变量相同的格式
- 静态变量命名使用大写下划线式
- 变量使用名词命名,方法使用动词命名,使命名清晰易懂,避免使用缩写
- 方法之间空一行
- 代码块之间空一行
- IDE设置为100列自动断行
- 代码中不能出现中文或者拼音
- 删除不使用的、跟程序无关的代码(变量、方法、文件等)
- 遵守不要重复自己原则(Don’t repeat yourself)
- 除非特殊说明,把缩写当作普通单词,遵循以上写法
- 类、资源和变量按照适用范围从大到下,命名从短到长
- 类、方法后的大括号隔开一个空格即可,不用另起一行
- 在函数或者封闭空间内,不要随意直接使用全局变量,而是使用传参的方式
- 登录使用login,登出使用logout,均作为一个单词
- 将模型分为业务模型(网络请求模型)和本地模型(视图模型)
- 减少继承,增加复用
- 引入的第三方库必须再添加一层封装,这样在更换第三方库的时候不需要更改代码
- 能在方法内作为参数的变量绝不生命为全局变量
- 能在单个控制器声明的变量绝不声明为应用全局变量
- 每次提交版本控制,尽量提交较少的更改
Android开发规范
开发工具规范
- 开发工具统一使用Android官方推荐的Android Studio
- 更改编码风格设置,私有成员变量添加m前缀
- 使用Android Studio自带的Gradle进行依赖管理
- 更改文件头部信息,如图覆盖设置,统一使用姓名全拼或者中文
- 不要在module中引用其它module
文件相关规范
- 类文件使用 - 大写驼峰式写法,如UserFragment,RootActivity
- 资源文件使用 - 小写下划线式写法,如fragmengt_user,activtiy_root
- 菜单文件命名跟布局命名类似,匹配对应的组件 
- 值文件命名规范为使用复数,如strings.xml 
- 资源文件中的 - 变量(name、id)采用驼峰式
- 所有 - xml文件默认采用小写下划线式
- 父类或基础模块命名为 - base
- 模块之间不交叉使用独立文件定义的键值,直接在文件中定义。 
- 使用独立文件放置跨文件(Fragment、Activity、UIViewController)的键值,其它键值否则定义在文件内。 
- 字符串资源名称(name)前缀 
| 类型 | 说明 | 前缀 | 例子 (name) | 
|---|---|---|---|
| 占位符 | placeholder | placeholderTitle | |
| 格式 | format | formatPrice | |
| Activity标题 | activity | activityUser | |
| 按钮标题 | button | buttonSubmitOrder | |
| 带冒号的说明文字 | label | labelUserName | |
| 度量单位 | unit | unitDollor | |
| 符号 | symbol | symbolMinus | |
| 提示 | 用于EditText的hint属性 | hint | hintOptional | 
| 标签 | tab | tabIndex | 
- 跟状态相关的文件使用以下命名方式:
| 状态 | 后缀 | 例子 | 
|---|---|---|
| 默认 | _normal | button_login_normal.png | 
| 按下 | _pressed | button_login_pressed.png | 
| 获得焦点 | _focused | button_login_focused.png | 
| 已禁用 | _disabled | button_login_disabled.png | 
| 已选择 | _selected | button_login_selected.png | 
- 图片文件命名规范:
| 类型 | 前缀 | 例子 | 说明 | 
|---|---|---|---|
| 标题图标 | ab_ | ab_stacked.png | |
| 普通按钮 | button_ | button_login_normal.png | |
| 对话框图标 | dialog_ | dialog_top.png | |
| 分隔线 | divider_ | divider_horizontal.9.png | |
| 普通图标 | icon_ | icon_star.png | |
| 菜单图标 | menu_ | menu_submenu_bg.9.png | |
| 通知图标 | notification_ | notification_bg.9.png | |
| 标签页图标 | tab_ | tab_home_selected.9.png | |
| 背景图 | background_ | background_user.png | |
| 占位图片 | placeholder_ | placeholder_goods_image.png | 因为有些图片需要请求网络,在获得网络图片资源之前,显示的图片叫占位图片 | 
- 布局文件命名规范:
| 组件 | 类名 | 布局命名 | 
|---|---|---|
| Activity | UserProfileActivity | activity_user_profile.xml | 
| Fragment | SignUpFragment | fragment_sign_up.xml | 
| Dialog | ChangePasswordDialog | dialog_change_password.xml | 
| AdapterView item | 无 | item_person.xml | 
| Banner | 无 | banner_guide.xml | 
| Partial layout | 无 | partial_title.xml | 
- 键值对中的键命名规范
| 常见键值对 | 键命名前缀 | 
|---|---|
| SharedPreferences | PREF_ | 
| Bundle | BUNDLE_ | 
| Fragment Arguments | ARG_ | 
| Intent Extra | EXTRA_ | 
| Intent Action | ACTION_ | 
如:
// 注意,变量名和变量的值保持一致
static final String PREF_EMAIL = "PREF_EMAIL";
static final String BUNDLE_AGE = "BUNDLE_AGE";
static final String ARG_USER_ID = "ARG_USER_ID";
// Intent相关的键命名要包含完整的包名
static final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";
static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER";
编码相关规范
- 禁止统一处理不同的异常,如:
try {
    someComplicatedIOFunction();        // may throw IOException
    someComplicatedParsingFunction();   // may throw ParsingException
    someComplicatedSecurityFunction();  // may throw SecurityException
} catch (Exception e) {                 // I'll just catch all exceptions
    handleError();                      // with one generic handler!
}
- 只引入必要的文件,使用import foo.Bar;而不是import foo.*;
- 私有非静态变量使用m前缀
- 私有静态变量使用s前缀
- 大括号下一行保留4个空格,如:
if (x == 1) {
    x++;
}
- 折行代码保留8个空格
Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);
- 覆盖父类的方法或者实现接口要在方法上方添加@Override注释
- 按照以下方式打印数据
Log.v(String TAG, String message);//详细
Log.d(String TAG, String message);//调试
Log.i(String TAG, String message);//信息
Log.w(String TAG, String message);//警告
Log.e(String TAG, String message);//错误
- 类成员采用以下顺序- Constants(常量)
- Fields(成员变量)
- ButterKnife(绑定视图)
- Setter and getter (成员变量的setter和getter方法)
- Constructors(构造函数)
- Override methods and callbacks (public or private)(重写函数和回掉函数)
- Public methods(公有方法)
- Private methods(私有方法)
- Inner classes or interfaces(内部类或接口)
 
- 生命周期函数按照生命周期排序,如:
public class MainActivity extends Activity {
    //Order matches Activity lifecycle
    @Override
    public void onCreate() {}
    @Override
    public void onResume() {}
    @Override
    public void onPause() {}
    @Override
    public void onDestroy() {}
}
- 在xml文件中,空元素要自己关闭,如
<TextView
    android:id="@+id/fragment_user_username_textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
iOS开发规范
开发工具规范
- 开发工具使用苹果官方的Xcode
- 开发工具必须从商店或官网下载,禁止复制未知来源的开发工具
- 使用http://alcatraz.io/管理Xcode第三方插件、主题和模板
- 使用https://cocoapods.org/和cocoapods-xcode-plugin进行依赖管理
- 电脑用户名设置为姓名全拼,Xcode会把这个值用在文件头部信息中
- 设置Organization和Class Prefix
- 尽可能使用const定义常量
- 按照Objective-C格式化风格进行格式化
编码相关规范
- 即使有命名空间限制,但是最好给每个组件都添加前缀
- 多个target 文件、公共方法(.h文件定义的方法)和变量要添加前缀
- 每个target中的每个类的每个方法只允许有一次method swizzle
- 使用#pragma mark - description对代码分块,方便查阅
- 类文件命名禁止缩写
- 常量命名采用首字母大写的驼峰式,宏命名采用大写下划线式。使用static和const声明普通常量,使用#define声明宏,如:
static NSString * const CompanyName = @"The Company";
static const CGFloat ImageHeight = 50.0;
#define DEBUG_MODE = 1;
- 使用.号获取和设置属性,如:
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
而不是采用以下形式:
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
- 错误处理采用以下方法:
NSError *error;
if (![self trySomethingWithError:&error]) {
    // Handle Error
}
而不是以下方式:
NSError *error;
[self trySomethingWithError:&error];
if (error) {
    // Handle Error
}
- 使用CGGeometry functions获取CGRect变量的属性,而不是直接访问,如:
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
而不是:
CGRect frame = self.view.frame;
CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;
- 常量使用以下方式定义:
static NSString* const CHECK_OUT_BUTTON_TITLE_FORMAT = @"去结算(%d)";
static CGFloat const SELLECT_ALL_BUTTON_TITLE_FONT = 12;
- 枚举类型使用以下方式定义:
typedef NS_EMUN(NSUInteger, LoginType) {
    SELLER,
    STORE_OWNER
};
即枚句类型的名称使用大写驼峰式的写法,值使用大写下划线式的写法
- 枚举类型使用按位掩码时,采用以下方式定义:
typedef NS_OPTIONS(NSUInteger, GoodsType) {
    NEW_GOODS  = 1 << 0,
    HOT_GOODS  = 1 << 1,
    BEST_GOODS  = 1 << 2
};
- 私有属性在类实现中定义,如:
@interface GoodsViewController ()
@property (nonatomic, strong) GADBannerView *googleAdView;
@property (nonatomic, strong) ADBannerView *iAdView;
@property (nonatomic, strong) UIWebView *adXWebView;
@end
- 不要直接和YES比较来判断是否为空或NO,采用以下方式:
if (!someObject) {}
if (someObject == nil) {}
if (isAwesome) {}
if (!someNumber.boolValue){}
if (someNumber.boolValue == NO){}
- 单例模式采用以下方法定义:
+ (instancetype)sharedInstance {
    static id sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[[self class] alloc] init];
    });
    return sharedInstance;
}
- 引入文件采用以下方式:
// Frameworks
@import QuartzCore;
// Models
#import "CommonUtil.h"
// Views
#import "CustomButton.h"
- pchFile.h引入的文件必须引入该文件必要的所有.h文件,即使pchFile已经引入了这些.h文件 
 这样保证pchFile移除某些文件不会导致其他文件出现错误
- 设计delegate时,第一个参数为发送信息的对象,如: 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- 按照以下格式声明成员变量,如:
@property(nonatomic, strong) UIScrollView *scrollView;
- 总是使用 - @property声明变量,而不是在括号中
- UIViewController代码顺序 
@property(nonatomic,strong)UIButton*button;
...
#pragma mark - life cycle
viewDidLoad
viewDidAppear
...
#pragma mark - UITableViewDelegate
#pragma mark - CustomDelegate
#pragma mark - event handlers
#pragma mark - private methods
#pragma mark - getters and setters
- 所有属性都使用getter和setter
- 所有View的初始化都放在getter中在 viewDidload里面只做addSubview和布局的事情,在viewDidAppear里面做Notification的监听之类的事情。至于属性的初始化,则交给getter去做。
- 所有点击事件的添加都写在初始化getter中
- 使用代码生成视图
- 监听Notification后记得释放
- 约束写在updateViewConstraints中,例如
-(void)updateViewConstraints{
    [super updateViewConstraints];
    [self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view).with.offset(20);
        make.left.equalTo(self.view).with.offset(20);
        make.right.equalTo(self.view).with.offset(-20);
    }];
    ...
}