云之讯语音、短信验证码实现

使用云之讯语音验证码功能,需要到云之讯开放平台去注册对应的账号,才能使用。

这里http://www.ucpaas.com/doc/doc_rest3-2.jsp 是官方文档 ,需要自己研究第一行文字,才能

明白业务功能的实现点。

下面是一个封装好的类,针对使用该SDK的帮助类:

//
//  HYBUCSSDKHelper.h
//  UCSVoiceOrSMSVerifyCodeDemo
//
//  Created by 黄仪标 on 15/2/2.
//

#import 
#import "UCSEvent.h"
#import "UCSService.h"

/*!
 * 云之讯UCS SDK铺助类,封装对IM、智能验证、VOIP网络电话功能
 * @author huangyibiao
 */
@interface HYBUCSSDKHelper : NSObject

/*!
 * 此处封装为单例
 */
+ (HYBUCSSDKHelper *)shared;

/*!
 *--------------------------------------------------------------------------
 * 下面的方法,是与云之讯平台连接相关的API
 *--------------------------------------------------------------------------*/

// 明文连接
- (NSInteger)connectWithClientNumber:(NSString *)clientNumber
                            password:(NSString *)clientPassword;

// 连接服务器(密文)
- (NSInteger)connect:(NSString *)token;

// 连接服务器(明文,指定IP,Port)
- (NSInteger)connect:(NSString *)hostAddress
                port:(NSString *)hostPort
        clientNumber:(NSString *)clientNumber
            password:(NSString *)clientPassword;

// 连接服务器(密文,指定IP,Port)
- (NSInteger)connect:(NSString *)hostAddress
            withPort:(NSString *)hostPort
           withToken:(NSString *)token;

// 获取与云之讯平台连接的状态
- (BOOL)isConnected;


/*!
 *--------------------------------------------------------------------------
 *         智能验证API
 *--------------------------------------------------------------------------*/
/**
 * 获取云验证码
 */
- (void)ucsVerifyCodeWithPhone:(NSString *)phone
                          seconds:(int)seconds;

/**
 * 验证码验证
 */
- (void)checkUcsVerifyCodeWithPhone:(NSString *)phone
                         verifycode:(NSString *)verifycode;

/*!
 *--------------------------------------------------------------------------
 *         语音验证码、短信验证码相关API
 *--------------------------------------------------------------------------*/
/**
 * 调起语音验证码接口
 */
- (void)voiceCodeTo:(NSString *)phone verifyCode:(NSString *)verifyCode;

/**
 * 调起短信验证码接口
 * @param phone 短信接收端手机号码集合,用英文逗号分开,每批发送的手机号数量不得超过100
 *              个(国内短信不要加前缀,国际短信号码前须带相应的国家区号,如日本:0081)
 * @param param 内容数据,用于替换模板中{数字},若有多个替换内容,用英文逗号隔开即可
 */
- (void)smsCodeTo:(NSString *)phone param:(NSString *)param;

@end

下面是实现文件,这里的网络库使用的是AFN:

#define kAccountSid @"" // 替换为您的sid
#define kAccountToken @""
#define kAppId @""
#define kAppName @""

#define kUCSBaseURL @"https://api.ucpaas.com"
#define kSoftVersion @"2014-06-30" // 云之讯REST API版本号。

@interface HYBUCSSDKHelper ()

@property (nonatomic, strong) UCSService *ucsService;
@property (nonatomic, copy)   NSString   *callerPhoneNumber; // 主叫号码
@property (nonatomic, copy)   NSString   *phoneNumber;       // 被叫号码

@end

@implementation HYBUCSSDKHelper

+ (HYBUCSSDKHelper *)shared {
  static HYBUCSSDKHelper *s_helper = nil;
  
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    if (s_helper == nil) {
      s_helper = [[[self class] alloc] init];
    }
  });
  
  return s_helper;
}

- (instancetype)init {
  if (self = [super init]) {
    self.ucsService = [[UCSService alloc] initWithDelegate:self];
  }
  return self;
}

/*!
 *--------------------------------------------------------------------------
 * 下面的方法,是与云之讯平台连接相关的API
 *--------------------------------------------------------------------------*/
// 明文连接
- (NSInteger)connectWithClientNumber:(NSString *)clientNumber password:(NSString *)clientPassword {
  return [self.ucsService connect:kAccountSid
                 withAccountToken:kAccountToken
                 withClientNumber:clientNumber
                    withClientPwd:clientPassword];
}

// 连接服务器(密文)
- (NSInteger)connect:(NSString *)token {
  return [self.ucsService connect:token];
}

// 连接服务器(明文,指定IP,Port)
- (NSInteger)connect:(NSString *)hostAddress
                port:(NSString *)hostPort
        clientNumber:(NSString *)clientNumber
            password:(NSString *)clientPassword {
  return [self.ucsService connect:hostAddress
                         withPort:hostPort
               withwithAccountSid:kAccountSid
                 withAccountToken:kAccountToken
                 withClientNumber:clientNumber
                    withClientPwd:clientPassword];
}

// 连接服务器(密文,指定IP,Port)
- (NSInteger)connect:(NSString *)hostAddress
            withPort:(NSString *)hostPort
           withToken:(NSString *)token {
  return [self.ucsService connect:hostAddress withPort:hostPort withToken:token];
}

// 查询帐号与服务器连接状态
- (BOOL)isConnected {
  return [self.ucsService isConnected];
}

/*!
 *--------------------------------------------------------------------------
 *         智能验证
 *--------------------------------------------------------------------------*/
/**
 * 获取云验证码
 */
- (void)ucsVerifyCodeWithPhone:(NSString *)phone
                       seconds:(int)seconds {
  [self.ucsService getVerificationCode:kAccountSid
                             withAppid:kAppId
                           withAppName:kAppName
                          withCodetype:1
                             withPhone:phone
                           withSeconds:seconds
                          withBusiness:1];
}

/**
 * 验证码验证
 */
- (void)checkUcsVerifyCodeWithPhone:(NSString *)phone
                         verifycode:(NSString *)verifycode {
  [self.ucsService doVerificationCode:kAccountSid
                            withAppid:kAppId
                            withPhone:phone
                       withVerifycode:verifycode];
}

/*!
 *--------------------------------------------------------------------------
 *         语音验证码、短信验证码相关API
 *--------------------------------------------------------------------------*/
/**
 * 调起语音验证码接口
 */
- (void)voiceCodeTo:(NSString *)phone verifyCode:(NSString *)verifyCode {
  AFHTTPRequestOperationManager *manager = [self operationManagerWithBaseUrl:kUCSBaseURL];
  
  // 获取系统当前的时间戳
  NSString *timestamp = [self timestamp];
  [manager.requestSerializer setValue:[self authorization:timestamp] forHTTPHeaderField:@"Authorization"];

  NSString *url = [NSString stringWithFormat:@"/%@/Accounts/%@/Calls/voiceCode?sig=%@",
                   kSoftVersion, kAccountSid, [self sig:timestamp]];
  NSDictionary *params = @{@"voiceCode" : @{@"appId"      : kAppId,
                                            @"to"         : phone,
                                            @"verifyCode" : verifyCode}};
  [manager POST:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"url: %@\nparmas: %@\nresponseObject:%@\nerrorMessage: %@ errorCode=%@ headers:%@",
                 operation.response.URL.absoluteString,
                 params,
                 responseObject,
                 responseObject[@"errorMessage"],
                 responseObject[@"errorCode"],
        operation.request.allHTTPHeaderFields);
    
    if ([responseObject isKindOfClass:[NSDictionary class]]) {
      NSLog(@"%@", responseObject);
    } else {
      
    }
  } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"error: %@", [error description]);
  }];
}

- (NSString *)timestamp {
  NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  [formatter setDateStyle:NSDateFormatterMediumStyle];
  [formatter setTimeStyle:NSDateFormatterShortStyle];
  [formatter setDateFormat:@"yyyyMMddHHmmss"];
  NSDate *datenow = [NSDate date];
  NSString *timestamp = [formatter stringFromDate:datenow];
  return timestamp;
}

- (NSString *)authorization:(NSString *)timestamp {
  // 使用Base64编码(账户Id + 冒号 + 时间戳)
  NSString *authorization = [NSString stringWithFormat:@"%@:%@", kAccountSid, timestamp];
  authorization = [self base64Encoding:authorization];
  return authorization;
}

- (NSString *)sig:(NSString *)timestamp {
  // URL后必须带有sig参数,sig= MD5(账户Id + 账户授权令牌 + 时间戳),共32位(注:转成大写)
  // 使用MD5加密(账户Id + 账户授权令牌 + 时间戳),共32位。
  NSString *sig = [NSString stringWithFormat:@"%@%@%@", kAccountSid, kAccountToken, timestamp];
  sig = [[self md5n:sig] uppercaseString];
  return sig;
}

/**
 * 调起短信验证码接口
 * @param phone 短信接收端手机号码集合,用英文逗号分开,每批发送的手机号数量不得超过100
 *              个(国内短信不要加前缀,国际短信号码前须带相应的国家区号,如日本:0081)
 * @param param 内容数据,用于替换模板中{数字},若有多个替换内容,用英文逗号隔开即可
 */
- (void)smsCodeTo:(NSString *)phone param:(NSString *)param {
  AFHTTPRequestOperationManager *manager = [self operationManagerWithBaseUrl:kUCSBaseURL];
  
  // 获取系统当前的时间戳
  NSString *timestamp = [self timestamp];
  [manager.requestSerializer setValue:[self authorization:timestamp] forHTTPHeaderField:@"Authorization"];

  NSString *url = [NSString stringWithFormat:@"/%@/Accounts/%@/Messages/templateSMS?sig=%@",
                   kSoftVersion, kAccountSid, [self sig:timestamp]];
  
  NSDictionary *params = @{@"templateSMS" : @{@"appId"      : kAppId,
                                              @"to"         : phone,
                                              @"templateId" : @(3177),
                                              @"param"      : param}};
  [manager POST:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"url: %@\nparmas: %@\nresponseObject:%@\nerrorMessage: %@ errorCode=%@ headers:%@",
          operation.response.URL.absoluteString,
          params,
          responseObject,
          responseObject[@"errorMessage"],
          responseObject[@"errorCode"],
          operation.request.allHTTPHeaderFields);
    
    if ([responseObject isKindOfClass:[NSDictionary class]]) {
      NSLog(@"%@", responseObject);
    } else {
      
    }
  } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"error: %@", [error description]);
  }];
}

/*!
 * @brief 将字符串转换成二进制数据后,再进行base64编码
 * @return 返回base64编码后的字符串
 */
- (NSString *)base64Encoding:(NSString *)str {
  NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
  NSString *result = nil;
  // 判断是否是ios7及其以上版本
#define kIsIOS7OrLater ([UIDevice currentDevice].systemVersion.integerValue >= 7 ? YES : NO)
  if (kIsIOS7OrLater) {
    result = [data base64EncodedStringWithOptions:0];
  } else {
    result = [data base64Encoding];
  }
  return result;
}

#pragma mark - md5加密
/*!
 * @brief 将字符串本身进行md5加密,并将加密后的字符串返回
 * @return 返回加密后的字符串
 */
- (NSString *)md5n:(NSString *)str {
  const char *cStr = [str UTF8String];
  unsigned char result[16];
  CC_MD5(cStr, strlen(cStr), result);
  return [NSString stringWithFormat:
          @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
          result[0], result[1], result[2], result[3],
          result[4], result[5], result[6], result[7],
          result[8], result[9], result[10], result[11],
          result[12], result[13], result[14], result[15]];
}

#pragma mark - UCCEventDelegate
// 与云通讯平台连接成功
- (void)onConnectionSuccessful:(NSInteger)result {
  NSLog(@"与云通讯平台连接成功 result=%ld", result);
}

// 与云通讯平台连接失败或连接断开
- (void)onConnectionFailed:(NSInteger)reason {
  NSLog(@" 与云通讯平台连接失败或连接断开 reason=%ld", reason);
}

/*!
 *--------------------------------------------------------------------------
 *         智能验证:语音验证码、短信验证码相关API代理回调
 *--------------------------------------------------------------------------*/
// 云获取验证码成功  0:已经验证成功,1:已下发验证码到用户
- (void) onGetValiateCodeSuccessful:(NSInteger)nResult {
  NSLog(@"%@", nResult ? @"已下发验证码到用户" : @"已经验证成功");
}

// 云获取验证码失败
- (void) onGetValiateCodeFailed:(NSInteger)reason {
  NSLog(@"云获取验证码失败 reason=%ld", reason);
}

// 云验证成功
- (void) onDoValiateCodeSuccessful:(NSInteger)nResult {
  NSLog(@"云验证成功 result=%ld", nResult);
}

// 云验证失败
- (void) onDoValiateCodeFailed:(NSInteger)reason {
  NSLog(@"云验证失败 reason=%ld", reason);
}

- (AFHTTPRequestOperationManager *)operationManagerWithBaseUrl:(NSString *)url {
  // 开启菊花转
  [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
  
  AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc]
                                            initWithBaseURL:[NSURL URLWithString:url]];
  manager.requestSerializer = [AFJSONRequestSerializer serializer];
  manager.responseSerializer = [AFJSONResponseSerializer serializer];
  manager.requestSerializer.stringEncoding = NSUTF8StringEncoding;
  [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
  [manager.requestSerializer setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
  [manager.requestSerializer setValue:@"256" forHTTPHeaderField:@"Content-Length"];
  manager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@"application/json",
                                                                            @"text/html",
                                                                            @"text/json",
                                                                            @"text/javascript"]];
  return manager;
}

@end

上面部分源码是无用的,因为这是为后面追加功能而添加的,这里只说明语音、短信验证码功能的实现。

说明:这里提供的部分源码,不意味着是好的代码,具体还请参考官方文档说明。

你可能感兴趣的:(云之讯语音、短信验证码实现)