拿来即用删掉即走:iOS客户端无侵入、一包任意环境切换实践篇

本篇以基于mPaaS框架的工程为例。

        在开发测试过程中需要在不同的环境中来进行,比如UAT、SIT、准生产。不同的阶段,不同的需求需要在不同环境测试。这样会引发两个问题:

1.工程庞大,源码文件好几G,每次切换环境需要修改宏定义,修改了宏定义就使得整个工程需要重新编译,而工程完整编译一次需要10多分钟,这样大大降低了开发效率;

 2.测试人员一次只能安装一个环境的测试包并且安装其他环境测试包则需要先卸载原来的安装包

网络上主流的环境切换也存在着各种各样的问题:

1. 设置Build Configuration:改变bundleid来达到一个手机安装多个测试包,每个测试包环境都不一样 这样会导致工程内比如登录中使用的安全键盘、扫描身份证的OCR插件、人脸识别的活体认证插件等需要验证bundleid的功能无法使用

 2.设置Settings.bundle :这是苹果提供的可以在iOS系统设置中添加设置选项的功能。但这样改会修改原有工程代码,上线整理生产代码会带来风险

3.开发一个切换环境的ViewController每次打开应用先选环境:这样首先会污染源代码其次如果不是100%源码工程是做不了的比如我们使用了mPaaS

本文首先先介绍两种iOS提供的比较强大的技术

1.分类(Category)Category主要作用是给原来的类添加新的方法。如果分类中的方法名与原类的方法名一致则会覆盖掉原类的这个方法。如果有两个分类都实现了与原类的方法名一样的方法则需要看编译顺序,只会调用最后编译的那个分类中的同名方法。

2.方法交换(method_exchange)主要作用是只要知道方法名就能替换任何一个类中的方法,而且替换后的方法还能继续调用原有的方法,包括系统的api。

这两种技术结合使用就能实现“拿来即用 用完即走"的环境切换理念。

这种方法不会污染源工程代码,打测试包时把关于切换环境的文件夹直接拖到工程里,打生产包把整个文件夹删掉。

之前的文章已经把思路说过了

使用mpaas的iOS客户端如何一包支持任意环境切换(理论篇)__小呵呵的博客-CSDN博客

这里更加清晰的描述一下

工程原本配置环境需要改的是

1.meta.config环境配置文件中的所有内容

2.info.plist xcode工程配置文件中的mPaaSCrypt

3.无线保镖图片(测试环境不验,不用管)

实现方法就是

1.重定向meta.config文件取值的是NSBundle-pathForResource:ofType:方法

2.重定向info.plist文件取值的是NSBundle-infoDictionary方法

准备好不同环境的config文件, 命名为metasit.config  metauat.config  meta准生产.config

然后核心代码就是

最早执行的load方法中写

{
        Method originalMethod = class_getInstanceMethod([NSBundle class], @selector(pathForResource:ofType:));
        Method swizzledMethod = class_getInstanceMethod([NSBundle class], @selector(pathForResource:ofTypeS:));
        method_exchangeImplementations(originalMethod, swizzledMethod);
        
 }
    {
        Method originalMethod = class_getInstanceMethod([NSBundle class], @selector(infoDictionary));
        Method swizzledMethod = class_getInstanceMethod([NSBundle class], @selector(infoDictionaryS));
        method_exchangeImplementations(originalMethod, swizzledMethod);
         
    }
NSBundle+YYY.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSBundle (YYY)

@end

NS_ASSUME_NONNULL_END
NSBundle+YYY.m


#import "NSBundle+YYY.h"
#import <objc/runtime.h>
@implementation NSBundle (YYY)
- (NSDictionary*)infoDictionaryS{
    
    NSMutableDictionary *dicc = [self infoDictionaryS].mutableCopy;
    //防止其他环境残留 影响
    [dicc removeObjectForKey:@"mPaaSInternal"];
    [dicc removeObjectForKey:@"mPaaS"];
    if ([[YYYPlistDataManage getCurrentEnvironmentFromPlist] containsString:@"uat"]){
        [dicc setObject:@{
                          @"Crypt":@YES,
                          @"GWWhiteList":@[@"http://*.*.*.*/mgw.htm",
                               @"http://*.*.*.*/mgw.htm",
                               @"http://*.*.*.*/mgw.htm",
                               @"http://*.*.*.*/mgw.htm",
                               @"http://*.*.*.*/mgw.htm",
                          @"PubKey":@"-----BEGIN PUBLIC KEY-----\n******\n-----END PUBLIC KEY-----",
                          @"RSA/ECC/SM2":@"SM2",
                          } forKey:@"mPaaSCrypt"];
        
    }else if ([[YYYPlistDataManage getCurrentEnvironmentFromPlist] containsString:@"sit"]){
        [dicc setObject:@{
                          @"Crypt":@YES,
                          @"GWWhiteList":@[@"http://*.*.*.*/mgw.htm",
                                           ],
                          @"PubKey":@"-----BEGIN PUBLIC KEY-----\n*********\n-----END PUBLIC KEY-----",
                          @"RSA/ECC/SM2":@"SM2",
                          } forKey:@"mPaaSCrypt"];

    }else if ([[YYYPlistDataManage getCurrentEnvironmentFromPlist] containsString:@"准生产"]){
        [dicc setObject:@{
                          @"Crypt":@YES,
                          @"GWWhiteList":@[@"http://#.#.#.#/mgw.htm"],
                          @"PubKey":@"-----BEGIN PUBLIC KEY-----\n#######\n-----END PUBLIC KEY-----",
                          @"RSA/ECC/SM2":@"SM2",
                          } forKey:@"mPaaSCrypt"];
        
    }
}




- (nullable NSString *)pathForResource:(nullable NSString *)name ofTypeS:(nullable NSString *)ext;
{
    if ([name containsString:@"Settings"]) {
        //排除掉蚂蚁提供的环境配置对功能的影响
        name = @"";
    }

    if([name containsString:@"meta"] && ([ext isEqualToString:@"config"])){
        if ([[YYYPlistDataManage getCurrentEnvironmentFromPlist] isEqualToString:@"uat"]) {
            name = @"metauat";
        }else if ([[YYYPlistDataManage getCurrentEnvironmentFromPlist] isEqualToString:@"sit"]){
            name = @"metasit";

        }else if ([[YYYPlistDataManage getCurrentEnvironmentFromPlist] isEqualToString:@"准生产"]){
            name = @"meta准生产";
        }


    return [self pathForResource:name ofTypeS:ext];
}

注意事项:

1.mpaas框架是在load方法中读取的配置信息,因此需要保证把我们的交换方法先执行。

2.mpaas也提供了环境切换方法,在我们代码里已经屏蔽掉了

3.再配置个弹框来选择切换哪个环境,选完后清数据并且exit,重新打开客户端切换完成

4.彻底清数据的方法,其他博客有写

5.蚂蚁官网demo中的两个文件字段样式是

6.展示效果示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值