본문 바로가기
모바일 APP/Swift

Objective c 네트워크 통신

by 살길바라냐 2023. 5. 25.
반응형

작성 이유 : 

Unityframwork에게 
accesstoken을 전달해야 하는 issue가 발생하여 

서버로 api 통신을 하는 메소드를 만들어야하는 작업이 생겼다. 

 

환경 : 

Unityframwork가 objective c로 되어 있어
핸들링도 objective c로 작성해야 한다.

 

서버에 요청하는 하는 메소드

// argument는 
// url : api를 요청할 url 주소
// postData : post 방식으로 사용시 body에 넣어줄 데이터 
+ (NSData *)request:(NSString *)method url:(NSString *)url postData:(NSData *)postData{=
	
    // result: completionHandler 핸들러의 결과 값을 저장할 변수 
    __block NSData * result = nil;
    
   	// NSMutableURLRequest : 서버에 api 요청하기 위한 scheme
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
    
    // url string 설정
    [request setURL:[NSURL URLWithString:url]];
    
    // start 헤더 세팅 ~
    NSString *authValue = [NSString stringWithFormat: @"Bearer %@",accessToken];
    [request setValue:authValue forHTTPHeaderField:@"Authorization"];
    
    NSString *postLength = [NSString stringWithFormat:@"application/json"];
    [request setValue:postLength forHTTPHeaderField:@"accept"];
    // ~  헤더 세팅 end
   
    // 만약 get 방식이라면
    if([method isEqualToString:@"GET"])
    {
        [request setHTTPMethod:@"GET"];
    }else{
    // 만약 post 방식이라면
        [request setHTTPMethod:@"POST"];
        [request setHTTPBody:postData];
    }
    
    
    // 서버의 응답을 비동기로 받기 위해 semaphore 시작
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    // NSURLSession : 네트위크 데이터 전송과 관련된 것을 조정하는 객체 
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    
    // dataTaskWithRequest : 지정한 url 요청 객체를 기준으로 내용을 검색하는 작업을 만든다. 
    [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
        if (error) {
            NSLog(@"error = %@", error);
            result = nil;
            
            // error발생으로 semaphore 종료
            dispatch_semaphore_signal(semaphore);
            return;
        }
        
        // network statusCode parsing
        NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
        
        // 200 ~ 500 때 조건일 경우 서버 데이터를 result 변수에 넣기
        if (statusCode >= 200 && statusCode < 500) {
            result = data;
        }
        
        // 서버에 응답을 받았기 때문에 semaphore 종료
        dispatch_semaphore_signal(semaphore);
        return;
    }]resume];
    
    // 위 작업을 끝날때 까지 대기
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    return result;
}

 

accesstoken을 요청하는 메소드

// 공통의 prefix url define
#define URL @"https://test.test.test"

// 서버에 요청 필요한 argument를 상황에 맞게 만들면 된다. 
// 나같은 경우에는 appkey, userid가 필요
(NSDictionary *)requestAccessToken:(NSString *)appKey userid:(NSString*)userId{
    
    // key  value 형식인 NSMutableDictionary에 데이터를 담아 return할 예정
    NSMutableDictionary *accessTokenStatus = [[NSMutableDictionary alloc] init];
    
    NSString *url = [NSString stringWithFormat:@"%@/client/auth/init",URL];
    
    // post method body
    NSString *postParams = [NSString stringWithFormat:@"appKey=%@&userId=%@",appKey,userId];
    
    // dataUsingEncoding: 옵션 형태에 맞는 NSData로 변환
    NSData *postData = [postParams dataUsingEncoding:NSUTF8StringEncoding];
    
    // 예외 처리를 위해 @try ~ catch 구문 사용
    @try{
    
    	// 위에 작성한 request 메소들 서버에 accesstoken 발급 요청
        NSData *result = [self request:@"POST" url:url postData:postData];
        
        // 서버에 응답 받은 데이터를 json 형태로 변환
        id json = [NSJSONSerialization JSONObjectWithData:result options:0 error:nil];
        
        //  조건에 따라 분기  
        if([json objectForKey:@"error"]){
            
            [accessTokenStatus setObject:@NO forKey:@"status"];
            [accessTokenStatus setObject:[[json objectForKey:@"error"] objectForKey:@"code"] forKey:@"accessToken"];
            [accessTokenStatus setObject:[[[json objectForKey:@"error"] objectForKey:@"desc"] objectAtIndex:0] forKey:@"errorMsg"];
            
            return accessTokenStatus;
        }
        
        // 전역으로 선언한 accessToken, refreshToken 변수에 서버에 응답 받은 토큰을 저장
        accessToken = [json objectForKey:@"accessToken"];
        refreshToken = [json objectForKey:@"refreshToken"];
        
        [accessTokenStatus setObject:@YES forKey:@"status"];
        
        return accessTokenStatus;
        
    } @catch (NSException *exception){
        
        [accessTokenStatus setObject:@NO forKey:@"status"];
        [accessTokenStatus setObject:@"NETWORK_ERROR" forKey:@"accessToken"];
        [accessTokenStatus setObject:@"네트워크 환경을 확인해주세요" forKey:@"errorMsg"];
        
        return accessTokenStatus;
    }
};

 

jwt 유효성 확인하는 메서드

(BOOL)validationAccessToken{
    
    // accessToken 전역변수에 저장여부를 확인
    // 저장이 안되어 있다면 유효성 확인이 불필요 하기 때문
    if(accessToken == nil){
        return NO;
    }
    
    NSString *jwtToken = accessToken;
    
    // 유효성을 expire 시간을 기준으로 하기 때문에 
    // 현재 시간을 unix 형태로 가져옴
    int currentTime = [[NSDate date] timeIntervalSince1970];
    
    // "."을 기준으로 string을 나누기
    NSArray *components = [jwtToken componentsSeparatedByString:@"."];
    
    // jwt .이 2개가 있기에 총 3개의 인덱스로 나눠지고
    // 기중 2번째 배열에 data 정보 즉 expire time이 있기에 그정보를 payloadBase64Url변수에 넣어준다.
    NSString *payloadBase64Url = components[1];
    NSString *payloadBase64 = [[payloadBase64Url stringByReplacingOccurrencesOfString:@"-" withString:@"+"] stringByReplacingOccurrencesOfString:@"_" withString:@"/"];
    
    // objective는 4bit 단위로 정확히 떨어지지 않으면 encode, decode가 불가능하다
    // 그래서 만약 4bit 단위로 맞지 않으면 임의 "=" 패딩 값을 넣어 맞춰줘서 decode 해야한다. 
    while ([payloadBase64 length] % 4 != 0) {
        payloadBase64 = [payloadBase64 stringByAppendingString:@"="];
    };
    
    // 4bit 단위로 맞춰준 jwt의 data값을 decoding 해준다. 
    NSData *payloadData = [[NSData alloc] initWithBase64EncodedString:payloadBase64 options:0];
    
    // json 형태로 변경해주고
    id json = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:nil];
    
    // expire time value를 비교 해준다. 
    if([[json objectForKey:@"exp"] intValue] > currentTime){
        return YES;
    }else{
        return NO;
    }
    
}
728x90

'모바일 APP > Swift' 카테고리의 다른 글

Objective C Enum을 -> Swift에서 사용하기  (0) 2023.06.26
S3 쉘스크립트 만들기  (1) 2023.04.05
Xcode 구조  (0) 2021.05.31
IOS 개발 조건  (0) 2021.05.31