본문으로 건너뛰기
버전: 1.0.0

우리 서비스에 맞는 예제 만들기

모바일 네이티브 앱 환경에 Webview 방식으로 eKYC를 연동해요.

유스비 담당자로부터 받은 메일의 첨부 파일에서 계정 정보를 확인할 수 있어요.
인증 진행 시, 계정 정보로 부여된 customer_id, id, key를 유스비 서버에 직접 전달하여 인증하는 방식이에요.

고객사에서 직접 만든 화면에서 엔드 유저의 필수 정보(이름, 생년월일, 휴대폰 번호, 이메일)를 받는 경우예요.

수집한 정보를 eKYC 서버에 직접 전달하는 기본 방식이에요.

기본 언어는 한국어로 제공되며, On 설정 시 영어로 제공돼요.

eKYC 기본 폰트 사용 시, Noto Sans KR로 제공돼요.

현재 선택한 플랫폼/언어에서 카메라 권한 등 필수 설정을 먼저 적용하세요.

JavaScript Packages
Code
"dependencies": {
...
"react-native-permissions": "^5.4.2",
"react-native-webview": "^13.15.0"
...
}


AndroidManifest.xml
Code
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />

Podfile
Code
def node_require(script)
# Resolve script with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
"require.resolve(
'#{script}',
{paths: [process.argv[1]]},
)", __dir__]).strip
end

node_require('react-native/scripts/react_native_pods.rb')
node_require('react-native-permissions/scripts/setup.rb')

setup_permissions([
'Camera',
])

Info.plist
Code
<key>NSCameraUsageDescription</key>
<string>카메라를 사용하여 사진을 촬영합니다.</string>

React Native 개발 환경 설정 안내
  • AndroidManifest.xml에 CAMERA 권한을 반드시 선언해야 카메라 접근이 가능합니다.
  • iOS Info.plist에 NSCameraUsageDescription을 추가해야 합니다.
  • iOS에서는 HTTPS 환경에서만 카메라 접근이 가능합니다.

선택한 설정에 맞는 eKYC 연동 코드예요.

React Native - CLI

import React, { Component } from 'react';
import {
StyleSheet,
Text,
PermissionsAndroid,
Platform,
SafeAreaView,
} from 'react-native';
import {
PERMISSIONS,
RESULTS,
requestMultiple,
checkMultiple,
} from 'react-native-permissions';
import { WebView } from 'react-native-webview';

export default class SampleApp extends Component {
constructor(props) {
super(props);

this.appWebview = null;
this.domain = 'https://kyc.useb.co.kr/auth';

this.state = {
permissionsGranted: false,
indexPage: { uri: this.domain + '?ver=1' },
};

this.handleCameraPermission();
}

handleCameraPermission = async () => {
if (Platform.OS === 'android') {
// Calling the permission function
const result = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.CAMERA,
]);

if (result['android.permission.CAMERA'] === 'granted') {
this.setPermissionsGranted(true);
} else {
this.setPermissionsGranted(false);
}
} else if (Platform.OS === 'ios') {
const res = await checkMultiple([PERMISSIONS.IOS.CAMERA]);

if (res[PERMISSIONS.IOS.CAMERA] === RESULTS.GRANTED) {
this.setPermissionsGranted(true);
} else {
console.log('Need Permission');
const res2 = await requestMultiple([PERMISSIONS.IOS.CAMERA]);
console.log('Permission Status' + JSON.stringify(res2));

if (res2[PERMISSIONS.IOS.CAMERA] === RESULTS.GRANTED) {
this.setPermissionsGranted(true);
} else {
this.setPermissionsGranted(false);
}
}
}
};

setPermissionsGranted = value => {
console.log('setPermissionsGranted', value);
this.setState({ permissionsGranted: value });
};

doneProcessHandler = msgData => {
if (msgData?.result) {
const resultData = msgData.result;
switch (resultData) {
case 'success':
console.log('success - KYC 작업이 성공했습니다.');
break;
case 'failed':
console.log('failed - KYC 작업이 실패했습니다.');
break;
case 'complete':
console.log('complete - KYC가 완료되었습니다.');
break;
case 'close':
console.log('close - KYC가 완료되지 않았습니다.');
break;
default:
console.log('알 수 없는 결과:', resultData);
break;
}
}
};

/**
* 화면에서 post를 던지면 react-native에서 받음(Throw a post on the screen, you will receive it from react-native)
*/
onReceivedWebViewMessage = event => {
console.log('onReceivedWebViewMessage', event.nativeEvent.data);
const decodedMsg = decodeURIComponent(Base64.atob(event.nativeEvent.data));

let msgData;
try {
msgData = JSON.parse(decodedMsg) || {};
this.doneProcessHandler(msgData);
} catch (error) {
console.error(error);
return;
}
};

onWebViewLoadEnd = () => {
console.log('onWebViewLoadEnd');
const customer_id = '2'; // all
let params = {
customer_id: "<고객사_id>", // number
id: "<client_id>", // string
key: "<client_secret>", // string
};
// Admin: [기타 설정] → [개인정보 옵션] → [사용자 필수 정보 수신 "사용 중"]
params.name = "홍길동";
params.birthday = "1984-11-23";
params.phone_number = "01012345678";
params.email = "test@test.com";

let encodedParams = Base64.btoa(encodeURIComponent(JSON.stringify(params)));
this.sendWebViewPostMessage(encodedParams);
};

/**
* 화면에서 post를 던지면 react-native에서 받음(Throw a post on the screen, you will receive it from react-native)
*/
sendWebViewPostMessage = message => {
console.log('sendWebViewPostMessage', message);
// console.log("sendWebViewPostMessage (decoded)", decodeURIComponent(Base64.atob(message)));
this.appWebview.postMessage(message);
};

render() {
return (
<SafeAreaView style={styles.container}>
{this.state.permissionsGranted && (
<WebView
style={styles.webview}
source={this.state.indexPage}
originWhitelist={['*']}
ref={webview => (this.appWebview = webview)}
javaScriptEnabled={true}
useWebKit={true}
mediaPlaybackRequiresUserAction={false}
domStorageEnabled={true}
allowsInlineMediaPlayback={true}
startInLoadingState={true}
allowUniversalAccessFromFileURLs={true}
onMessage={this.onReceivedWebViewMessage}
onLoadEnd={this.onWebViewLoadEnd}
/>
)}
{!this.state.permissionsGranted && (
<Text>
카메라/갤러리 접근 권한이 없습니다. 권한 허용 후 이용해주세요. // no
access authority for camera and gallery. check allowance of
authortiy.
</Text>
)}
</SafeAreaView>
);
}
}

const chars =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const Base64 = {
btoa: (input = '') => {
let str = input;
let output = '';

for (
let block = 0, charCode, i = 0, map = chars;
str.charAt(i | 0) || ((map = '='), i % 1);
output += map.charAt(63 & (block >> (8 - (i % 1) * 8)))
) {
charCode = str.charCodeAt((i += 3 / 4));

if (charCode > 0xff) {
throw new Error(
"'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.",
);
}

block = (block << 8) | charCode;
}

return output;
},

atob: (input = '') => {
let str = input.replace(/[=]+$/, '');
let output = '';

if (str.length % 4 == 1) {
throw new Error(
"'atob' failed: The string to be decoded is not correctly encoded.",
);
}
for (
let bc = 0, bs = 0, buffer, i = 0;
(buffer = str.charAt(i++));
~buffer && ((bs = bc % 4 ? bs * 64 + buffer : buffer), bc++ % 4)
? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))
: 0
) {
buffer = chars.indexOf(buffer);
}

return output;
},
};

const styles = StyleSheet.create({
container: {
flex: 1,
},
webview: {
flex: 1,
},
});

더 궁금한 내용이 있나요?에러 코드 및 대응
코드 샘플을 참고하세요eKYC Github
기술지원이 필요하신가요?이메일 보내기