B11-MSTR移动app的二次开发(iOS)

二次开发方案

一、方案的确定及要实现的效果

       首先,最多的信息获取还是官方文档:https://lw.microstrategy.com/msdz/MobileUpdates/941_iOSU5/docs/mergedProjects/mobile_sdk/mobilesdk.htm

       iOS的开发其实只在本项目的一小部分,项目需求也是改来改去,最终需要实现的有:

  1. 应用图标的替换,应用名称的更改,启动图片的替换。
  2. 自定义登录界面。
  3. 登录时进行VPN验证,通过VPN服务器实现外网访问。
  4. 动态更改app的显示模式(文件夹目录或者默认报表)。
  5. 服务器集群,负载均衡的使用。

二、实现步骤

      1、需求一的实现很简单,图标更改在Images.xcassets里面直接替换。应用名称在Info_IPad.plist,Bundle display name对应的名字改掉就可以。

      2、由于mstr的工程只有一个main.m文件可以看到。所以要想在原app的基础上进行二次开发,首先要创建一个自定义的CustomAppDelegate.h  CustomAppDelegate.m文件。此部分详解在文档的目录为:Home > Mobile SDK > Mobile SDK for iOS > Customizing MicroStrategy Mobile > Customization scenarios > Adding functionality with a custom Application Delegate。    

//
//  CustomAppDelegate.m
//  MicroStrategyMobile
//
//  Copyright (c) 2014 MicroStrategy Inc. All rights reserved.
//

#import "CustomAppDelegate.h"
#import "CustomLoginView.h"
#import <MicroStrategyMobileSDK/MSIAuthenticationModule.h>
#import <MicroStrategyMobileSDK/MSIAuthenticationPromptViewController.h>
#import <MicroStrategyMobileSDK/MSIMobileLoginManager.h>

@implementation CustomAppDelegate
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    BOOL res = [super application:application didFinishLaunchingWithOptions:launchOptions];
    //add custom logic here

    return res;
}
@end

      创建自定义的登录界面

      需要创建CustomLoginView.h  CustomLoginView.m文件。可参照文档目录:Home > Mobile SDK > Mobile SDK for iOS > Customizing authentication > Client-side customizations > Programmatic customizations > Customizing login screen UI and authentication parameters programmatically

 

#import "CustomLoginView.h"

@implementation CustomLoginView

- (void) setupWithParameters:(NSDictionary*) promptViewParameters delegate:(id<MSIMobileLoginPromptViewDelegate>) delegate{

    [super setupWithParameters:promptViewParameters delegate:delegate];
    //After calling super, add additional code to setup the login UI, for example, add textfields, login buttons, background image

    
}

-(void) login{

    [self.delegate loginPromptView:self didInputAuthenticationParameters:@{

         @"username":([usernameTextField text]?[usernameTextField text]:EMPTY_STRING),

         @"password":([passwordTextField text]?[passwordTextField text]:EMPTY_STRING)

    }];

}

@end

      同时CustomAppDelegate.m文件也要做更改

//
//  CustomAppDelegate.m
//  MicroStrategyMobile
//
//  Copyright (c) 2014 MicroStrategy Inc. All rights reserved.
//

#import "CustomAppDelegate.h"
#import "CustomLoginView.h"
#import <MicroStrategyMobileSDK/MSIAuthenticationModule.h>
#import <MicroStrategyMobileSDK/MSIAuthenticationPromptViewController.h>
#import <MicroStrategyMobileSDK/MSIMobileLoginManager.h>
#import <MicroStrategyMobileSDK/ProjectInfo.h>

@implementation CustomAppDelegate

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{    

    CustomLoginView *loginView = [[CustomLoginView alloc] initWithFrame:self.window.frame];

    MSIAuthenticationPromptViewController *loginViewController = [[MSIAuthenticationPromptViewController alloc] init];

    MSIAuthenticationModule *loginModule = [[MSIAuthenticationModule alloc] init];

    [[MSIMobileLoginManager sharedMobileLoginManager] setView:loginView controller:loginViewController module:loginModule forPromptType:AuthenticationPromptType];

    BOOL res = [super application:application didFinishLaunchingWithOptions:launchOptions];

    return res;
}

@end

      其实MSIAuthenticationPromptViewController也可以创建再继承,用来监听登录的成功和失败,文档目录:Home > Mobile SDK > Mobile SDK for iOS > Customizing authentication > Client-side customizations > Programmatic customizations > Adding custom logic during authentication process。

       到此,自定义登录界面已经实现。

    3、VPN服务器的认证和使用

      在iOS平台下,第三方应用程序通过调用移动应用安全认证开发包,使用证书与VPN服务器建立安全通道、以及单点登录等功能的实现。此处以北京国富安提供的开发包为例(具体细节参照国富安提供的开发文档)。

  1. 首先在iPad端安装移动认证证书(国富安提供)。
  2. 从Keychain里读取证书的cn。设置指定CN的证书,用此证书来做为身份。根据身份证书去跟vpn建立ssl连接。
  3. 根据VPN上配置的资源,启动本地监听的端口
  4. 通过VPN调用服务器接口,获取配置文件
  5. 显示登录界面,点击登录,根据证书和主账号密码进行统一安全认证。
  6. 认证成功返回的json,包含移动平台用户的主从账号信息,并会在Keychain中存储session,附应用可以通过Keychain中存储的session直接登录成功
  7. 根据json信息,将主账号作为mstr用户账号和mstr用户默认密码一起,在应用内自动进行mstr的认证。成功界面会跳转,不跳转且无提示可以检查所使用mstr用户是否存在。(注:以移动平台主账号为账号,自定义统一的默认密码,提前在mstr创建用户)

      

/**
 *  2、从设备的钥匙串中获取证书,如果获取失败就返回nil;
 *  @return 证书或者nil
 */
-(NSString *)getCNfromKeychain
{
    NSMutableArray *outArray = [[NSMutableArray alloc] init];
    //获取证书cn项,因为有可能有多个证书,所以返回的是一个cn项的数组
    BOOL ret = [[CertHelper sharedInstance] getCNfromKeychain:outArray];
    if (!ret)
    {
        NSLog(@"获取证书失败,请联系管理员");
        return nil;
    }
    //一般情况只有一个证书
    NSString *certCN = [outArray objectAtIndex:0];
    return certCN;
}

if ([[CertHelper sharedInstance] setIndexbyCN:[self getCNfromKeychain]] == -1) //指定身份证书,返回-1表示设置指定证书失败
    {
        NSLog(@"your identity error");
    }

/**
 * 将身份证书和VPN做认证以登录VPN创建ssl连接
 *  @return VPN连接状态
 */
-(BOOL)connectVPN
{
    int iResult = -1;
    @try {
        iResult =[[L4Proxy sharedInstance] L4Proxy_ShakeHands_With_VPN:kVPNServer IPPort:kVPNPort username:@"" password:@""];
    }
    @catch (NSException *exception) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"网络连接失败" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
        [alertView show];
        return NO;
    }
    @finally {
        if (iResult != 0) {
            NSLog(@"VPN 登录失败");
            return NO;
        }else {
            NSLog(@"VPN 登录成功");
            return YES;
        }
    }
}
// 3、获取监听端口
- (void)refreshConnectionInfo
{
    Constants* constants = [Constants sharedInstance];
    int webPort = [[L4Proxy sharedInstance] startLocalListen:@"BI-8080"];
    int port = [[L4Proxy sharedInstance] startLocalListen:@"BI-34952"];
    
    if(webPort > 0) {
        constants.webPort = webPort;
        constants.webServer = LOCAL_HOST;
    }
    
    if(port > 0) {
        constants.port = port;
        constants.iserver = LOCAL_HOST;
    }
}
/*
    5、6、点击登陆时调用的方法,将密码输入框的参数传过来,返回证书的主从账号信息,并会在Keychain中存储session,附应用可以通过调用相应的方法找到Keychain中存储的session直接登录成功
*/
- (Account *)ssoLogin:(NSString*) password
{
    int ssoLocalListenPort = [[L4Proxy sharedInstance] startLocalListen:ssoDesStr];
    if (ssoLocalListenPort > 0) {
        NSString *ssoHost = [NSString stringWithFormat:@"https://%@:%d",LOCAL_HOST, ssoLocalListenPort];
        NSString *retJson = [[SsoAuth sharedInstance] ssoAuthByCert:password withAppID:appId withServerAddress:ssoHost];
        NSLog(@"retJson = %@", retJson);
        NSError *error = nil;
        NSDictionary* result = [NSJSONSerialization JSONObjectWithData:[retJson dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&error];
        NSLog(@"%@",result);
        if (error == nil && [@"success" isEqualToString:[result objectForKey:@"status"]]) {
            if(_account == nil) {
                _account = [[Account alloc] init];
            }
            _account.name = [result objectForKey:@"masterAccout"];
            _account.token = [result objectForKey:@"token"];
            return _account;
        } else {
            NSString *message = [result objectForKey:@"message"];
            if(message == nil)
            {
                message = @"请检查网络";
            }
            UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:@"确认" otherButtonTitles:nil, nil];
            [alertView show];
            
            NSLog(@"单点登录JSON解析失败, error:%@", error);
            return nil;
        }
    } else {
        return nil;
    }
}

      4、动态更改app的显示模式(文件夹目录或者默认报表)

      上步的第4步骤,通过VPN调用服务器接口,获取配置文件,就是为了获取XML文件,每次启动都重新获取XML文件,所以可以在后台对XML文件内容进行更改,下次启动的时候,就会显示新更改的模式。

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSString *str = [NSString stringWithFormat:@"http://127.0.0.1:%d/MicroStrategy/findDocumentId?loginname=%@",constant.webPort,certName];
    NSString *urlString = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    NSURLResponse *response = nil;
    NSError *error = nil;
    NSData *allStringdata = [NSURLConnection  sendSynchronousRequest:request returningResponse:&response error:&error];
    NSString *allString = [[NSString alloc] initWithData:allStringdata encoding:NSUTF8StringEncoding];
    //保存到沙盒目录下
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSString *xmlPath1 = [path stringByAppendingString:@"/Preferences.xml"];
    [allString writeToFile:xmlPath1 atomically:YES encoding:NSUTF8StringEncoding error:nil];
    return YES;
}

         XML文件的获取,用浏览器登录mstr的mobile server,在mobile配置的地方,进行主屏幕的配置。之后会在mstr服务器的安装路径下找到一个刚生成的XML文件,例如,D:\apache-tomcat-6.0.36\webapps\MicroStrategyMobile\WEB-INF\xml\mobile。

         注意:取出的XML文件需要把服务器地址改为本地,端口号改为本地监听端口,项目地址不改。

      5、服务器集群,负载均衡的使用。

         负载均衡的使用,不需要app作何更改。由于VPN的使用app中只有本地地址127.0.0.1和监听端口号的存在。同样配置文件XML文件,里面的项目地址也无须更改。

posted @ 2015-06-09 15:07  朱亚男  阅读(873)  评论(0编辑  收藏  举报