[2020기록] 보안키패드 적용 (WebView, AndroidNative) - sonsangjun/SimpleTechDesc GitHub Wiki

참고

명칭 설명
결과값을 받아야하는 Activity http://zeany.net/54

개발환경

명칭 내용
OS Windows 10
IDE AndroidStudio 4.0.1
MinVer 14
MaxVer 28
제공 INCA nProtect

개발중에...

WebView에서 보안키패드Activity (nprotect)

WebView의 InputTag를 터치시, 보안키패드가 포함된 액티비티가 나타난다. 하지만, 그 액티비티 설계도를 어디서 setContent하는지 java코드에 나와 있지 않다. 아래 내용은 먼 미래에 참고할지 모르는 내용을 적어놓는다.

// example코드 기준
0 .@javascriptinterface로 등록된 WebviewActivity의 setKeyCrypt를 호출시
1. setKeyCrypt의 keypadMngHelper.configureInputBoxAndStart 호출
2. IxKeypadManageHelper의 this.a 호출
3. a에서 Intent var3 생성, 대상 Activity는 IxCustomInputActivity
4. IxCustomInputActivity의 onCreate 내 int var4에 this.b.getIdentifier를 통해 zix_custom_input.xml 정보 삽입
5. this.setContentView(var4)를 통해 액티비티 생성 (흔히 보는 테스트 보안키패드 화면)

2번부터는 class내부를 살펴본 내용으로,
라이브러리 영역이라서 더 이상 확인은 불가능하다.

결론은 액티비티를 다른 걸로 갈아끼우기는 어렵고, zix_custom_input.xml 파일을 수정해야한다.
(설계상)

WebView에 보안키패드에서 입력되는 족족 보이게 하기

제공된 가이드에 나와있지 않아, 여기에 기술한다.

// 소스를 확인하지 못했지만, 신한카드가 가장 가깝게 구현되어있다. (로그상으로는 INCA제품임)
// IxKeypadManageHelper의 setSecureKeypadEventListener 설정시.
// IxKeypadManageHelper.setSecureKeypadEventListener 를 새로 생성한다. 
// 그리고, 안에 함수가 추상함수라서 모두 구현이 필요한데,
// 그 중에.
//
// public void onInputChanged 함수를 Override해야한다.
// 최종적으로는 JS의 전역함수 setKeycryptResult를 호출함으로서 화면에 기록된다.

// 오버라이드
@Override
public void onInputChanged(EditText arg0, int arg1) {
    // 입력길이가 바뀔때마다, 웹뷰상에 보여주도록 Overriding (20.09.28)
    Log.d(DEBUG_TAG,"arg0 : "+arg0+", arg1 : "+arg1);
    IxResultItem[] resultItem = keypadMngHelper.getInputResults();
    setKeycryptResult(resultItem);
}

/**
 * 보안 키패드 입력 데이터를 웹 페이지로 전달
 * <p>
 * view.loadUrl때문에 keycryptm.js import가 꼭 필요하다. (하필이면 전역메소드를 호출함)
 */
private static void setKeycryptResult(IxResultItem[] resultItem) {
    // 웹뷰 객체
    WebView view = null;
    try{
        view = (WebView)callMethod("getCurrentMPWebView");
    }catch(Exception e){
        Log.e(DEBUG_TAG,"setKeycryptResult, getCurrentMPWebView call fail");
        return;
    }

    if ( null != resultItem && null != resultItem[0] ) {
        IxResultItem inputResult = resultItem[0];

        // 입력창에 넣을 더미 문자 생성
        StringBuilder dummy = new StringBuilder();
        for (int i = 0; i < inputResult.getEncDataLen(); i++) {
            dummy.append("*");
        }

        view.loadUrl("javascript:setKeycryptResult('" + inputConfig.getLabel() + "','" + inputConfig.getUid() + "','" + inputResult.getEncData() + "','" + inputResult.getKey() + "','" + dummy.toString() + "')");
    }
}



문제내용

Duplicate Class...android-v4...(android 28.0.0)

기존 프로젝트에 새 Activity 생성 후에 발생하는 문제라면, 생성한 액티비티의 extends 를 확인한다. 일반적인 Activity가 아니라 appComActivity 같은 다른 액티비티를 상속받고 있으면, 기존 API 버전에 해당하는 Activity Lib와 충돌을 일으킨다. (appComActivity를 상속받는다는 것은 API 28 jar가 gradle에 자동으로 세팅되었음을 의미하고, 해당 Lib를 땡겨오면서 Build시, 기존 Lib와 충돌을 일으킴)

해결법은 기존 Activity 버전을 생성한 Activity 버젼에 맞추거나. 생성한 Activity 버전을 기존 Activity를 생성한 버전에 맞추는 것이다.

아마, 기존 버전에 맞추는게 훨씬 비용이 적을 것 같다. (기존 Activity가 뭘 상속받는지 체크해서 신규Activity 상속을 똑같이 맞추면 된다.)

보안키패드가 포함된 Activity가 뜨지 않음.

1. 먼저 정상적인 경로를 통해 Activity를 생성했는가?

직접 Java Class로 생성시. androidManifest.xml에 등록되지 않는다. 이 경우, 앱 자체가 죽는다. (Java에서 Exception 발생)

보안키패드 Input 터치시 죽음.

Activity를 정상적으로 만들었다는 가정하에. 또 확인해야할 사항이. 보안키패드 자체 Activity가 androidManifest.xml에 등록되어 있는지 확인필요. 아래는 오류로그 전문이다.

// 제품은 inca Keypad

2020-09-04 11:33:49.711 6857-6857/__[패키지경로 회사명 감춤]__ D/ViewRootImpl@17ee2ab[newKeypadActivity]: ViewPostIme pointer 0
2020-09-04 11:33:49.718 6857-6857/__[패키지경로 회사명 감춤]__ E/InputEventReceiver: Exception dispatching input event.
2020-09-04 11:33:49.718 6857-6857/__[패키지경로 회사명 감춤]__ E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
2020-09-04 11:33:49.721 6857-6857/__[패키지경로 회사명 감춤]__ E/MessageQueue-JNI: android.content.ActivityNotFoundException: Unable to find explicit activity class {__[패키지경로 회사명 감춤]__/com.nprotect.keycryptm.IxCustomInputActivity}; have you declared this activity in your AndroidManifest.xml?
        at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2069)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1717)
        at android.app.Activity.startActivityForResult(Activity.java:5252)
        at android.app.Activity.startActivityForResult(Activity.java:5203)
        at com.nprotect.keycryptm.IxKeypadManageHelper.a(Unknown Source:236)
        at com.nprotect.keycryptm.IxKeypadManageHelper$1.a(Unknown Source:12)
        at com.nprotect.keycryptm.a.e.onTouch(Unknown Source:18)
        at android.view.View.dispatchTouchEvent(View.java:14371)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.widget.ScrollView.dispatchTouchEvent(ScrollView.java:857)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:736)
        at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1952)
        at android.app.Activity.dispatchTouchEvent(Activity.java:4038)
        at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:694)
        at android.view.View.dispatchPointerEvent(View.java:14643)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:6539)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:6326)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5764)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5817)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5783)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5939)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5791)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5996)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5764)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5817)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5783)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5791)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5764)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:8976)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:8837)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:8790)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:9112)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:194)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:336)
        at android.os.Looper.loop(Looper.java:197)
        at android.app.ActivityThread.main(ActivityThread.java:8125)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.ja
2020-09-04 11:33:49.721 6857-6857/__[패키지경로 회사명 감춤]__ D/AndroidRuntime: Shutting down VM
    
    
    --------- beginning of crash
2020-09-04 11:33:49.723 6857-6857/__[패키지경로 회사명 감춤]__ E/AndroidRuntime: FATAL EXCEPTION: main
    Process: __[패키지경로 회사명 감춤]__, PID: 6857
    android.content.ActivityNotFoundException: Unable to find explicit activity class {__[패키지경로 회사명 감춤]__/com.nprotect.keycryptm.IxCustomInputActivity}; have you declared this activity in your AndroidManifest.xml?
        at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2069)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1717)
        at android.app.Activity.startActivityForResult(Activity.java:5252)
        at android.app.Activity.startActivityForResult(Activity.java:5203)
        at com.nprotect.keycryptm.IxKeypadManageHelper.a(Unknown Source:236)
        at com.nprotect.keycryptm.IxKeypadManageHelper$1.a(Unknown Source:12)
        at com.nprotect.keycryptm.a.e.onTouch(Unknown Source:18)
        at android.view.View.dispatchTouchEvent(View.java:14371)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.widget.ScrollView.dispatchTouchEvent(ScrollView.java:857)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3863)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:3492)
        at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:736)
        at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1952)
        at android.app.Activity.dispatchTouchEvent(Activity.java:4038)
        at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:694)
        at android.view.View.dispatchPointerEvent(View.java:14643)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:6539)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:6326)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5764)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5817)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5783)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5939)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5791)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5996)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5764)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5817)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5783)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5791)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5764)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:8976)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:8837)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:8790)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:9112)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:194)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:336)
        at android.os.Looper.loop(Looper.java:197)
        at android.app.ActivityThread.main(ActivityThread.java:8125)
        at java.lang.reflect.Method.invoke(Native Method)
2020-09-04 11:33:49.723 6857-6857/__[패키지경로 회사명 감춤]__ E/AndroidRuntime:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)

중간즈음에, com.nprotect.keycryptm.IxCustomInputActivity}; have you declared this activity in your AndroidManifest.xml? 라며 물어보는 부분이 존재한다.

이런식으로 추가하면 된다.

<!-- ========================== KeyCryptM start ========================== -->
<activity android:name="com.nprotect.keycryptm.IxCustomInputActivity"
	android:excludeFromRecents="true"
	android:theme="@android:style/Theme.Translucent"
	android:configChanges="keyboardHidden|orientation|screenSize" />
<!-- ========================== KeyCryptM end ========================== -->

등록 후, 오류가 해결되었는지 체크한다.