웹뷰 INTENT 설정

KAKAO 로그인 / TOSS 결제

Posted by ETHAN KIM on April 15, 2023 · 8 mins read
Android Java

작업

  • 웹뷰 내 카카오 앱 및 결제 앱 사용 시 디바이스로부터 앱 호출
  • 앱이 없을 경우 fallback url (카카오로그인) / 플레이스토어 앱 마켓 호출


실습 환경

  • Winodws / Android Emulator(version 11, API30) / device : galaxyS8


구현 결과


androidManifest.xml 설정

  • 호출되는 앱 스킴 세팅
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.packagename">

    <queries>
        <package android:name="com.kakao.talk" />
        <!-- 토스 -->
        <package android:name="viva.republica.toss" />
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="supertoss" />
        </intent>
        <!-- 삼성카드 -->
        <package android:name="kr.co.samsungcard.mpocket" />
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="mpocket.online.ansimclick" />
        </intent>
        <!-- 현대카드 -->
        <package android:name="com.hyundaicard.appcard" />
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="hdcardappcardansimclick" />
        </intent>
        <!-- 현대카드공인인증서 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="smhyundaiansimclick" />
        </intent>
        <!-- 우리카드앱카드 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="wooripay" />
        </intent>
        <!-- 신한카드앱카드 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="shinhan-sr-ansimclick" />
        </intent>
        <!-- 신한카드공인인증서 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="smshinhanansimclick" />
        </intent>
        <!-- 국민카드앱카드 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="kb-acp" />
        </intent>
        <!-- 롯데카드모바일결제 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="lottesmartpay" />
        </intent>
        <!-- 롯데카드앱카드 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="lotteappcard" />
        </intent>
        <!-- 하나카드앱카드 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="cloudpay" />
        </intent>
        <!-- 농협카드-앱카드 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="nhappvardansimclick" />
        </intent>
        <!-- 농협카드공인인증서 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="nonghyupcardansimclick" />
        </intent>
        <!-- 씨티카드공인인증서 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="citicardappkr" />
        </intent>
        <!-- ISP모바일 -->
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="ispmobile" />
        </intent>
    </queries>

    <uses-permission android:name="android.permission.INTERNET" />
  ...

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:hardwareAccelerated="true"
        android:icon="@mipmap/alldeal_launch"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:supportsRtl="true"
        android:theme="@style/Theme.Alldeal"
        android:usesCleartextTraffic="true"
        tools:targetApi="31">
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
        <activity
            android:name=".IntroActivity"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:padding="0dp" />
        <service
            android:name=".MyFireBaseMessagingService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
    </application>

</manifest>
}


Activity 파일 내 웹뷰 설정

  • WebViewClient Class 선언
  • shouldOverrideUrlLoading 메소드 오버라이드
  • intent url에 대한 분기처리
    // ------------------------- WEBVIEW CLIENT (INTENT SETTING) -------------------------- //
    private class WebViewClientClass extends WebViewClient {
        @Override                                   // 1) Loading
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            pBar.setVisibility(View.VISIBLE);       // Show Loading
        }
        @Override                                   // 2) Start
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            pBar.setVisibility(View.GONE);          // Hide Loading
        }

        @TargetApi(Build.VERSION_CODES.N)
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            //Log.d("WebViewClient URL : " , request.getUrl().toString());
            if (request.getUrl().getScheme().equals("intent")) {
                try {
                    // Intent 생성
                    Intent intent = Intent.parseUri(request.getUrl().toString(), Intent.URI_INTENT_SCHEME);

                    // 실행 가능한 앱이 있으면 앱 실행
                    if (intent.resolveActivity(getPackageManager()) != null) {
                        startActivity(intent);
                        //Log.d(TAG, "ACTIVITY: " + intent.getPackage());
                        return true;
                    }

                    // Fallback URL이 있으면 현재 웹뷰에 로딩
                    String fallbackUrl = intent.getStringExtra("browser_fallback_url");
                    if (fallbackUrl != null) {
                        view.loadUrl(fallbackUrl);
                        //Log.d(TAG, "FALLBACK: " + fallbackUrl);
                        return true;
                    }

                    // 앱이 설치되어 있지 않으면 마켓으로 이동
                    Intent marketIntent = new Intent(Intent.ACTION_VIEW);

                    //카카오링크 예외처리
                    String packageName;
                    if(request.getUrl().toString().contains("kakaolink")){
                        packageName = "com.kakao.talk";
                    }else{
                        packageName = intent.getPackage();
                    }

                    marketIntent.setData(Uri.parse("market://details?id=" + packageName));
                    if (marketIntent.resolveActivity(getPackageManager()) != null) {
                        startActivity(marketIntent);
                        //Log.d(TAG, "MARKET: " + intent.getPackage());
                        return true;
                    }

                    //Log.e(TAG, "Could not parse anything");

                } catch (URISyntaxException e) {
                    //Log.e(TAG, "Invalid intent request", e);
                }
            }

            view.loadUrl(request.getUrl().toString());
            return true;
            //return super.shouldOverrideUrlLoading(view, request);
        }