{"id":21654506,"url":"https://github.com/wujunyang/jiamoduledemo","last_synced_at":"2025-04-04T19:08:57.496Z","repository":{"id":94338096,"uuid":"68163224","full_name":"wujunyang/jiaModuleDemo","owner":"wujunyang","description":"一个针对iOS模块化开发的解决方案(不断完善优化中)","archived":false,"fork":false,"pushed_at":"2017-10-26T09:38:17.000Z","size":51090,"stargazers_count":714,"open_issues_count":3,"forks_count":205,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-03-28T18:09:21.053Z","etag":null,"topics":["ios","module","podspec"],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wujunyang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-09-14T01:47:41.000Z","updated_at":"2025-02-20T03:27:38.000Z","dependencies_parsed_at":"2023-04-07T10:34:06.432Z","dependency_job_id":null,"html_url":"https://github.com/wujunyang/jiaModuleDemo","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wujunyang%2FjiaModuleDemo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wujunyang%2FjiaModuleDemo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wujunyang%2FjiaModuleDemo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wujunyang%2FjiaModuleDemo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wujunyang","download_url":"https://codeload.github.com/wujunyang/jiaModuleDemo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247234921,"owners_count":20905854,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","module","podspec"],"created_at":"2024-11-25T08:28:04.943Z","updated_at":"2025-04-04T19:08:57.472Z","avatar_url":"https://github.com/wujunyang.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# jiaModuleDemo\n\njiaModuleDemo项目是为了解决关于项目中如何进行模块化开发而编写的实例，包含如何进行路由式、本地模块间交互的实现；目前还是在页面层级进行抽离，对于项目中各个模块共有的基础功能也进行提取，可以结合私有Pods进行管理；\n\n# 项目中存在的问题\n```obj-c\n问题一：页面耦合严重\n```\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/7.png\" width=800px height=400px\u003e\u003c/img\u003e\n\n上面这张图中左边体现了目前项目中存在的问题，对于页面之间相互耦合，而页面之间的传参也各不相同，由于不同的开发人员或者简便方式等原因，传参的类型都有差异，包含如实体、简单基本类型等，先前项目对于路由方式也不支持，导致要实现收到消息推送进行不同的页面跳转存在硬编码情况，对于功能扩展存在相当大的问题；而右边则是模块化后页面之间的交互方式；页面之间也不存在耦合关系，都只跟JiaMediator这个中介者相依赖；而传参都统一成以字典的形式；虽然可能牺牲一些方便跟随意，却可以解耦模块化；并且加入对路由方式的处理；约定好相关的协议进行交互；用这种路由方式代替那些第三方的路由插件则是因为它的灵活性，最主要还是省去了第三方路由插件在启动时要注册路由的问题；\n\n```obj-c\n问题二：相同模块重复开发\n```\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/9.png\" width=800px height=400px\u003e\u003c/img\u003e\n\n当公司里面有多个项目同时进行，并且有可能是多个人分别不同项目时，就会存在如上图出现的情况，其实每个APP中都是有很多共同的模块，当然有可能你会把相同功能模块代码复制一份在新项目中，但这其实并不是最好的方式，在后期不断迭代过程中，不同的人会往里面增加很多带有个人色彩的代码；这样就像相同的模块项目后期对于多个项目统一管理也是灾难性，有可能会失控，哪怕项目转移别人接手也会无形中浪费很多时间，增加维护成本，所以实例中更注重对于一些相同模块进行提取，求同存异；而模块化结合私有Pods进行管理，对于常用功能的封装，只要开放出一些简单开关配置方式，就可以实现一个功能，比如日志记录、网络请求模块、网络状态变化提示等；\n\n\n# 模块化解决方案\n\n### 页面交互解耦\n\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/1.png\" width=500px height=400px\u003e\u003c/img\u003e\n\n```obj-c\n\n```\n\n实现调用代码：\n\n```obj-c\nNSDictionary *curParams=@{kDesignerModuleActionsDictionaryKeyName:@\"wujunyang\",kDesignerModuleActionsDictionaryKeyID:@\"1001\",kDesignerModuleActionsDictionaryKeyImage:@\"designerImage\"};\n    switch (indexPath.row) {\n        case 0:\n        {\n            UIViewController *viewController=[[JiaMediator sharedInstance]JiaMediator_Designer_viewControllerForDetail:curParams];\n            [self presentViewController:viewController animated:YES completion:nil];\n            break;\n        }\n        case 1:\n        {\n            UIViewController *viewController=[[JiaMediator sharedInstance]JiaMediator_Designer_viewControllerForDetail:curParams];\n            [self.navigationController pushViewController:viewController animated:YES];\n            break;\n        }\n        case 2:\n        {\n            NSString *curRoue=@\"jiaScheme://Designer/nativeFetchDetailViewController?name=wujunyang\u0026ID=1001\u0026image=designerImage\";\n            UIViewController *viewController=[[JiaMediator sharedInstance]performActionWithUrl:[NSURL URLWithString:curRoue] completion:^(NSDictionary *info) {\n                \n            }];\n            [self.navigationController pushViewController:viewController animated:YES];\n            break;\n        }\n        default:\n            break;\n    }\n```\n`上面针对本地模块调用及路由方式调用的跳转`\n\n1：JiaMediator起到一个中介的作用，所有的模块间响应交互都是通过它进行，每个模块都会对它进行扩展分类（例如：JiaMediator+模块A），分类主要是为了用于本地间调用而又不想用路由的方式，若要用路由的方式则要注意关于路由约束准确编写，它将会直接影响到能否正确响应到目标；\n\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/3.png\" width=200px height=400px\u003e\u003c/img\u003e\n\n2：JiaMediator是每个模块都要用到的内容，可以把它放在公共的模块中，因为关于各个模块的JiaMediator由每个模块自个负责，开放给要调用的模块使用；\n\n\n\n3：为了解耦对于页面间的传参都采用字典形式，项目中所有的页面都继承于一个基页面jiaBaseViewController，里面已经有对初始化对于字典参数的接收并赋值，每个模块的子页面只要调用parameterDictionary属性，就可以获取关于参数的内容；同样jiaBaseViewController也是每个模块都要使用，所以也被提取在公共里面，其还包括一些导栏条的封装及关于网络状态变化的提示等；\n\n\n\n```obj-c\n\n//页面接收参数\n@property(nonatomic,strong)NSDictionary *parameterDictionary;\n//初始化参数\n- (id)initWithRouterParams:(NSDictionary *)params;\n\n\n- (id)initWithRouterParams:(NSDictionary *)params {\n    self = [super init];\n    if (self) {\n        _parameterDictionary=params;\n        NSLog(@\"当前参数：%@\",params);\n    }\n    return self;\n}\n```\n\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/2.png\" width=500px height=400px\u003e\u003c/img\u003e\n\n4：当响应某一个模块目标后，将会把相应的viewController进行返回，而对于具体如何操作则是在获得当前控制器自行处理，比如是跳转还是弹出展现；\n\n5：为了减少对于字典参数key拼写错误问题，每个模块都有一个对应key值的常量配置文件，已经把对应的key值都定义成的常量，方便调用；\n\n```obj-c\n#ifndef HeaderDesignerConfig_h\n#define HeaderDesignerConfig_h\n\n//键值\nstatic NSString * const kDesignerModuleActionsDictionaryKeyName=@\"name\";\nstatic NSString * const kDesignerModuleActionsDictionaryKeyID=@\"ID\";\nstatic NSString * const kDesignerModuleActionsDictionaryKeyImage=@\"image\";\n\n#endif /* HeaderDesignerConfig_h */\n\n```\n\n```obj-c\n\n NSDictionary *curParams=@{kDesignerModuleActionsDictionaryKeyName:@\"wujunyang\",kDesignerModuleActionsDictionaryKeyID:@\"1001\",kDesignerModuleActionsDictionaryKeyImage:@\"designerImage\"};\n\n```\n\n### JiaCore(基础功能封装)\n\nJiaCore是整个APP最基础模块，所有的模块化都要依赖，主要包含一些全局的功能模块，比如JiaBaseViewController、JiaAppDelegate等；目前已经把一些默认的功能进行集成在里面，包含网络状态变化判断及提示、日志记录功能等；并把一些相关配置的内容用JiaCoreConfigManager这个管理类进行统一设置，比如是否打开日志记录功能；JiaCoreConfigManager类则是开放给具体APP设置全局的相关配置；下面就以其中一个日志记录功能进行讲解:\n\n```obj-c\n//JiaCore基础模块相关配置\nJiaCoreConfigManager *jiaCoreConfig=[JiaCoreConfigManager sharedInstance];\njiaCoreConfig.recordlogger=YES;\n```\n然后具体APP的PrefixHeader.pch引入命名空间并进行设置记录日志的等级：\n```obj-c\n#import \"JiaCocoaLumberjack.h\"\n\n//DDLog等级\nstatic const int ddLogLevel = DDLogLevelVerbose;\n```\n这样就完成的一个APP对于日志记录模块的引入，JiaCore已经帮你完成的关于日志记录的相关配置，并且错误内容以一种可读性较好的格式记录到file文件中，而且这些file文件生成规则也都定义好了，当然如何时你要是在Xcode控制台显示不同等级色彩，只要安装XcodeColors插件并简单进行设置就可以了，对于不同等级不同色彩都已经在JiaCore配置完成；\n\n在JiaCore里面也默认集成了热更新的功能，只要传入简单的对象数组就会启动热更新；其中JiaPathchModel已经是定义好的模型，在APP中把接口请求转化成模型数组，其中patchId是唯一值名称、md5则是JS文件的MD5值、url是JS的下载路径、ver则是对哪个版本起作用；因为一般我们在外面的APP都是多版本共存，热更新也要进行版本区分，只下载与本版本相对应的热更新JS文件加载；而MD5值则是为了增加安全性，避免JS文件被别人进行修改而影响APP的运行，在JiaCore会对下载后的JS文件进行MD5计算并比较；对于没有在jSPatchMutableArray以前的JS文件会被删除；\n\n```obj-c\n//热更新内容\nJiaPathchModel *sample=[[JiaPathchModel alloc]init];\nsample.patchId = @\"patchId_sample1\";\nsample.md5 = @\"2cf1c6f6c5632dc21224bf42c698706b\";\nsample.url = @\"http://test.qshmall.net:9090/demo1.js\";\nsample.ver = @\"1\";\n    \nJiaPathchModel *sample1=[[JiaPathchModel alloc]init];\nsample1.patchId = @\"patchId_sample2\";\nsample1.md5 = @\"e8a4eaeadce5a4598fb9a868e09c75fd\";\nsample1.url = @\"http://test.qshmall.net:9090/demo2.js\";\nsample1.ver = @\"1\";\n\n//JiaCore基础模块相关配置\nJiaCoreConfigManager *jiaCoreConfig=[JiaCoreConfigManager sharedInstance];\njiaCoreConfig.jSPatchMutableArray=[@[sample,sample1] mutableCopy];\n```\n\n### JiaNetWork(网络交互封装)\n\n对于网络请求模块则采用YTKNetwork，底层还是以AFNetworking进行网络通信交互，定义一个继承于YTKBaseRequest的JiaBaseRequest，针对JiaBaseRequest则是为了后期各个APP可以对它进行分类扩展，对于一些超时、请求头部等进行统一个性化设置，毕竟这些是每个APP都不相同；而针对模块中关于请求网络的前缀设置，则在每个模块中都有一个单例的配置类，此配置类是为了针对该模块对不同APP变化而定义；相应的配置内容开放给APP，由具体APP来定义，例如现在项目中的JiaBaseRequest+App.h类，里面有简单设置超时跟头部；当然记得把这个分类引入到APP中，比如AppPrefixHeader这个APP的全局头部；\n\n```obj-c\n#import \"JiaBaseRequest+App.h\"\n\n@implementation JiaBaseRequest (App)\n\n- (NSTimeInterval)requestTimeoutInterval {\n    return 15;\n}\n\n//公共头部设置\n- (NSDictionary *)requestHeaderFieldValueDictionary\n{\n    NSDictionary *headerDictionary=@{@\"platform\":@\"ios\"};\n    return headerDictionary;\n}\n\n@end\n```\n\n```obj-c\n网络层整体实现如下：\n```\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/4.png\" width=500px height=400px\u003e\u003c/img\u003e\n\n\n\n### JiaGT模块(个推封装)\n\n消息推送对于一个APP是相当重要性，一般是采用第三方的SDK进行集成，其实大部分的SDK处理代码都是差不多，在这实例中对差异化的内容进行提取，实例中将以个推进行模块化，因为消息推送的大部分代码都集中在AppDelegate中，造成的一大堆杂乱代码，当然也有一部分人对AppDelegate进行扩展分类进行移除代码，实例中将采用另外一种解决方案进行抽取，可以达到完全解耦，在具体的APP里面将不会再出现个推SDK相关内容，只要简单进行配置跟处理消息就可以，下面只是简单的列出部分代码，其它封装代码见源代码；\n```obj-c\n//设置个推模块的配置\njiaGTConfigManager *gtConfig=[jiaGTConfigManager sharedInstance];\ngtConfig.jiaGTAppId=@\"0uuwznWonIANoK07JeRWgAs\";\ngtConfig.jiaGTAppKey=@\"26LeO4stbrA7TeyMUJdXlx3\";\ngtConfig.jiaGTAppSecret=@\"2282vl0IwZd9KL3ZpDyoUL7\";\n```\n```obj-c\n#pragma mark 消息推送相关处理\n\n/**\n *  @author wujunyang, 16-07-07 16:07:25\n *\n *  @brief  处理个推消息\n *\n *  @param NotificationMessage\n */\n-(void)gtNotification:(NSDictionary *)NotificationMessage\n{\n    NSLog(@\"%@\",NotificationMessage[@\"payload\"]);\n    NSLog(@\"－－－－－接收到个推通知------\");\n}\n\n\n/**\n *  @author wujunyang, 16-07-07 16:07:40\n *\n *  @brief  处理远程苹果通知\n *\n *  @param RemoteNotificationMessage\n */\n-(void)receiveRemoteNotification:(NSDictionary *)RemoteNotificationMessage\n{\n    NSLog(@\"%@\",RemoteNotificationMessage[@\"message\"]);\n    NSLog(@\"－－－－－接收到苹果通知------\");\n}\n\n/**\n *  @author wujunyang, 16-09-21 14:09:33\n *\n *  @brief 获得注册成功时的deviceToken 可以在里面做一些绑定操作\n *\n *  @param deviceToken \u003c#deviceToken description#\u003e\n */\n-(void)receiveDeviceToken:(NSString *)deviceToken\n{\n    NSLog(@\"－－－－－当前deviceToken：%@------\",deviceToken);\n}\n```\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/5.png\" width=500px height=400px\u003e\u003c/img\u003e\n\n上面能够对个推进行完全的解耦不得不提一个第三方的插件XAspect，如果想对它进行了解可以在github进行查找；它的主要作用如下图，可以用它进行其它第三方SDK的抽离\n\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/6.png\" width=500px height=400px\u003e\u003c/img\u003e\n\n\n### JiaAnalytics模块(友盟统计封装)\n\nJiaAnalytics模块是在友盟统计SDK跟Aspect相结合基础上完成，对于页面的进出统计采用Aop切面方式进行，把原本应该在每个页面生命周期的统计代码移除，App运用只要简单配置友盟相对应的信息，也可以设置要统计页面的过滤条件，目前已经有三种如要统计的开头页面的前缀字符串数组、要统计的页面名称字符串数组、不统计的页面名称字符串数组；可以结合使用，达到精确统计页面的目的；而且把统计的代码放在异步线程进行，不会影响主线程的响应；\n\n```obj-c\n__weak typeof(self) ws = self;\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n        \n        [UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id\u003cAspectInfo\u003e info, BOOL animated){\n            UIViewController *controller = [info instance];\n            BOOL filterResult=[ws fileterWithControllerName:NSStringFromClass([controller class])];\n            if (filterResult) {\n                [ws beginLogPageView:[controller class]];\n            }\n        } error:NULL];\n        \n        [UIViewController aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionAfter usingBlock:^(id\u003cAspectInfo\u003e info, BOOL animated){\n            UIViewController *controller = [info instance];\n            BOOL filterResult=[ws fileterWithControllerName:NSStringFromClass([controller class])];\n            if (filterResult) {\n                [ws endLogPageView:[controller class]];\n            }\n        } error:NULL];\n    });\n\n```\n\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/10.png\" width=500px height=400px\u003e\u003c/img\u003e\n\n\n### JiaShare模块(友盟分享及第三方登录封装)\n\nJiaShare模块运用友盟分享最新版的SDK进行封装，并把一些其它不是很常用的去除，目前只支持新浪、微信聊天、微信朋友圈、QQ聊天页面、qq空间、腾讯微博；分享包括纯文本、图文、URL、视频地址、音乐地址，并在里面已经运用JavaScriptCore.framework封装好关于H5页面调用分享并传参的功能；可以直接在UIWebView里面进行调用；本模块只是对功能进行封装，对于友盟在info.plist的配置还是要自行手动，如不明白可以直接到友盟分享官网查看，项目到也有配置好一份可以直接参考；JiaPlatformHelper类里面有一个判断当前手机是否有安装相应平台软件的方法，可以用它进行隐藏相应的操作功能，避免上架时审核不过；下面的代码是在项目的AppDelegate里面进行配置\n\n```obj-c\n//友盟分享\nJiaShareConfigManager *jiaShareConfig=[JiaShareConfigManager sharedInstance];\njiaShareConfig.shareAppKey=@\"57e3f1cbe0f55a42080011ec\";\njiaShareConfig.shareLogEnabled=YES;\n//设置平台\n[jiaShareConfig setPlaform:JiaSocialPlatConfigType_Tencent appKey:@\"100424468\" appSecret:@\"c7394704798a158208a74ab60104f0ba\" redirectURL:@\"http://www.umeng.com/social\"];\n[jiaShareConfig setPlaform:JiaSocialPlatConfigType_Wechat appKey:@\"wxdc1e388c3822c80b\" appSecret:@\"3baf1193c85774b3fd9d18447d76cab0\" redirectURL:@\"http://www.umeng.com/social\"];\n[jiaShareConfig setPlaform:JiaSocialPlatConfigType_Sina appKey:@\"3921700954\" appSecret:@\"04b48b094faeb16683c32669824ebdad\" redirectURL:@\"http://sns.whalecloud.com/sina2/callback\"];\n```\n\n然后就可以进行分享，在ViewController里面进行调用，JiaSocialPlatformType是分享平台的枚举，shareUrlDataWithPlatform为URL分享方式，其它可以直接见源代码JiaShareHelper类\n\n```obj-c\n    [JiaShareHelper shareUrlDataWithPlatform:JiaSocialPlatformType_WechatSession withShareUrl:@\"http://www.sina.com.cn\" withTitle:@\"新浪\" withDescr:@\"新浪网页\" withThumImage:@\"http://dev.umeng.com/images/tab2_1.png\" withCompletion:^(id result, NSError *error) {\n        if(error)\n        {\n            NSLog(@\"分享出错了\");\n        }\n    }];\n```\n\n如果有加载H5页面，而且也要进行分享的功能就可以使用JiaWebShareHelper,因为使用到的是JavaScriptCore，所以只能用在UIWebView中，如果你要是使用WKWebView可以自个再进行封闭，下面是加载H5页面中的webViewDidFinishLoad代码；\n\n```obj-c\n- (void)webViewDidFinishLoad:(UIWebView *)webView {\n    self.jsContext = [webView valueForKeyPath:@\"documentView.webView.mainFrame.javaScriptContext\"];\n    // 通过模型调用方法，这种方式更好些。\n    JiaWebShareHelper *shareHelper  = [[JiaWebShareHelper alloc] init];\n    self.jsContext[@\"jia\"] = shareHelper;\n    shareHelper.jsContext = self.jsContext;\n    shareHelper.webView = self.webView;\n    \n    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {\n        context.exception = exceptionValue;\n        NSLog(@\"异常信息：%@\", exceptionValue);\n    };\n}\n```\n\nH5中就可以很方便直接进行：\n\n```obj-c\n\u003cinput type=\"button\" value=\"分享QQ纯文本\" onclick=\"jia.shareText('qq','你好，我是测试')\"\u003e\n        \n\u003cinput type=\"button\" value=\"分享微信URL\" onclick=\"jia.shareUrl('wechatsession','http://www.sina.com','你好，我是测试','测试用','http://dev.umeng.com/images/tab2_1.png')\"\u003e\n            \n\u003cinput type=\"button\" value=\"分享微信朋友圈URL\" onclick=\"jia.shareUrl('wechattimeline','http://www.sina.com','你好，我是测试','测试用','http://dev.umeng.com/images/tab2_1.png')\"\u003e\n                        \n\u003cinput type=\"button\" value=\"分享QQ空间图文\" onclick=\"jia.shareImageText('qzone','http://dev.umeng.com/images/tab2_1.png','你好，我是测试','测试用','http://dev.umeng.com/images/tab2_1.png')\"\u003e\n```\n\n下面简单介绍关于第三方登录跟获取用户信息的功能，其功能代码放在JiaPlatformHelper里面，已经对授权成功及获取用户信息都有回去调相应的参数回来：\n\n```obj-c\nif(![JiaPlatformHelper installPlatAppWithType:JiaSocialPlatformType_QQ])\n{\n    [weakSelf showResult:@\"没有安装QQ软件,将此功能隐藏\"];\n    return;\n}\n            \n[JiaPlatformHelper authWithPlatform:JiaSocialPlatformType_QQ withCompletion:^(NSString *uid, NSString *openid,NSString *accessToken, NSError *error) {\n    if (error) {\n        NSLog(@\"出错了\");\n        return;\n          }\n                \n    NSString *result=[NSString stringWithFormat:@\"获得到的值为：uid:%@--token:%@--openid:%@\",uid,accessToken,openid];\n    [weakSelf showResult:result];\n}];\n```\n\n获取用户信息的代码如下：\n\n```obj-c\n[JiaPlatformHelper getUserInfoWithPlatform:JiaSocialPlatformType_QQ withCompletion:^(NSString *name, NSString *iconUrl, NSString *gender, NSError *error) {\n   if (error) {\n      NSLog(@\"出错了\");\n      return;\n    }\n                \n   NSString *result=[NSString stringWithFormat:@\"获得到的值为：name:%@--性别:%@\",name,gender];\n   [weakSelf showResult:result];\n}];\n```\n\n关于取消授权也有相应的方法：\n\n```obj-c\n[JiaPlatformHelper cancelAuthWithPlatform:JiaSocialPlatformType_QQ withCompletion:^(id result, NSError *error) {\n   if (error) {\n      NSLog(@\"出错了\");\n      return;\n     }\n                \n   NSString *ressult=@\"取消成功\";\n   [weakSelf showResult:ressult];\n}];\n```\n\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/11.png\" width=500px height=400px\u003e\u003c/img\u003e\n\n# 模块化结合私有Pods方案\n上面实例中只是把相关模块化的提取都在一个工程进行体现，最后还是要落实结合Pods进行管理，把每个模块分开管理，不同的APP可以简单通过Pods指令就可以达到引入模块的效果，对于一些相同模块可以在不同的APP重复引用，减小重复开发成本；\n\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/8.png\" width=700px height=500px\u003e\u003c/img\u003e\n\n在本项目中已经引入的Pod来管理目前开发的几个模块，并导入在我目前的Github的一个库里Spec进行统一管理，首先要引入Pod来管理则要增加jiaModule.podspec文件；\n\n```obj-c\nPod::Spec.new do |s|\n\ns.name         = \"jiaModule\"\ns.version      = \"0.0.9\"\ns.summary      = \"iOS模块化功能的引用\"\n\ns.homepage     = \"https://github.com/wujunyang/jiaModuleDemo\"\ns.license      = { :type =\u003e \"MIT\", :file =\u003e \"FILE_LICENSE\" }\ns.author             = { \"wujunyang\" =\u003e \"wujunyang@126.com\" }\n\ns.platform     = :ios, \"7.0\"\n\ns.source       = { :git =\u003e \"https://github.com/wujunyang/jiaModuleDemo.git\", :tag =\u003e \"#{s.version}\" }\n\ns.requires_arc = true\n\ns.subspec 'JiaCore' do |jiaCore|\njiaCore.source_files = 'jiaModuleDemo/BaseModule/JiaCore/**/*.{h,m}'\njiaCore.dependency 'XAspect'\njiaCore.dependency 'YYCache'\njiaCore.dependency 'JSPatch'\njiaCore.dependency 'RealReachability'\njiaCore.dependency 'FLEX', '~\u003e 2.0'\njiaCore.dependency 'CocoaLumberjack', '~\u003e 2.0.0-rc'\njiaCore.dependency 'AFNetworking', '~\u003e 3.0'\nend\n\ns.subspec 'JiaGT' do |jiaGT|\njiaGT.source_files = 'jiaModuleDemo/BaseModule/JiaGT/**/*'\njiaGT.dependency 'jiaModule/JiaCore'\njiaGT.dependency 'XAspect'\njiaGT.dependency 'GTSDK'\nend\n\ns.subspec 'JiaAnalytics' do |jiaAnalytics|\njiaAnalytics.source_files = 'jiaModuleDemo/BaseModule/JiaAnalytics/**/*'\njiaAnalytics.dependency 'jiaModule/JiaCore'\njiaAnalytics.dependency 'XAspect'\njiaAnalytics.dependency 'Aspects'\njiaAnalytics.dependency 'UMengAnalytics-NO-IDFA', '~\u003e 4.1.1'\nend\n\n\ns.subspec 'JiaShare' do |jiaShare|\njiaShare.source_files = 'jiaModuleDemo/BaseModule/JiaShare/**/*'\njiaShare.dependency 'jiaModule/JiaCore'\njiaShare.dependency 'XAspect'\njiaShare.dependency 'UMengUShare/UI'\njiaShare.dependency 'UMengUShare/Social/Sina'\njiaShare.dependency 'UMengUShare/Social/WeChat'\njiaShare.dependency 'UMengUShare/Social/QQ'\njiaShare.dependency 'UMengUShare/Social/TencentWeibo'\nend\n\n\n\ns.frameworks = 'UIKit'\n\n# s.xcconfig = { \"HEADER_SEARCH_PATHS\" =\u003e \"$(SDKROOT)/usr/include/libxml2\" }\n# s.dependency \"JSONKit\", \"~\u003e 1.4\"\nend\n\n\n```\n\n上面的文件会把不同的模块进行分离，可以一起引入也可以单独引入某一个模块；pod会自动把相应的依赖都引入,下面是全部引入关于jiaModule模块\n\n```obj-c\nsource 'https://github.com/CocoaPods/Specs.git'\nsource 'https://github.com/wujunyang/WjySpecs.git'\nplatform :ios, \"7.0\"\n\npod 'jiaModule'\n```\n\n假如要引入只是其中一个模块：\n\n```obj-c\nsource 'https://github.com/CocoaPods/Specs.git'\nsource 'https://github.com/wujunyang/WjySpecs.git'\nplatform :ios, \"7.0\"\n\npod 'jiaModule/JiaCore’\npod 'jiaModule/JiaGT’\n```\n\n下面简单介绍两条关于验证跟提交jiaModule.podspec的指令，都要打开终端进入项目根目录，也就是jiaModule.podspec所在的目录，然后进行执行；\n\n```obj-c\n#验证是否正确（后面还有一个git的私有地址)\npod lib lint jiaModule.podspec --allow-warnings --use-libraries --sources=https://github.com/CocoaPods/Specs.git,https://github.com/wujunyang/WjySpecs.git\n\n#提交到库  (specs就是你们的私有库名，见下面repo add指令时的名字，后面还有一个git的私有地址)\npod repo push specs jiaModule.podspec --allow-warnings --use-libraries --sources=https://github.com/CocoaPods/Specs.git,https://github.com/wujunyang/WjySpecs.git\n```\n\n注意：如果提交到库时报下面的问题，说明还没有把私有仓库集下载到本地：\n\n```obj-c\n[!] Unable to find the `specs` repo. If it has not yet been cloned, add it via `pod repo add`.\n```\n\n可以直接执行指令（specs名字可以自行定义，跟上面提交时对应该上就行）：\n\n```obj-c\npod repo add specs https://github.com/wujunyang/WjySpecs.git\n```\n\n会在路径：/Users/自个电脑用户名/.cocoapods/repos（被隐藏，要用指令进行显示出来） 下有一个文件夹specs 另外还有一个是Pod官网的文件夹；\n\n最后还要登录Git账号跟密码，就可以成功提交了\n\n```obj-c\nUsername for 'https://github.com': wujunyang@126.com\nPassword for 'https://wujunyang@126.com@github.com': \nTo https://github.com/wujunyang/WjySpecs.git\n   80ca876..d4f7446  master -\u003e master\n```\n\n# 订阅号\n\n最近有个妹子弄的一个关于扩大眼界跟内含的订阅号，每天都会更新一些深度内容，在这里如果你感兴趣也可以关注一下(嘿对美女跟知识感兴趣)，当然可以关注后输入数字：5  会有我的微信号，如果有问题你也可以在那找到我；当然不感兴趣无视此信息；\n\n\n\u003cimg src=\"https://github.com/wujunyang/jiaModuleDemo/blob/master/jiaModuleDemo/ProjectImage/dy.jpg\" width=200px height=200px\u003e\u003c/img\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwujunyang%2Fjiamoduledemo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwujunyang%2Fjiamoduledemo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwujunyang%2Fjiamoduledemo/lists"}