Custom Tab을 이용한 하이브리드 앱을 업로드 했는데 에러가 발생했다.

 

content.ActivityNotFoundException : No Activity found to handle intent ... 뭐라고 나왔다.

두번째 이미지를 봤을때 딱 봐도 최신 기기가 아닌 옛날 기기에서 에러가 발생했다.

그랬을 때 유추해볼 수 있는 건 그 기기에 내가 사용한 기능이 없을 것 같다.

우선 어떤 기능인지 알면 SDK 버전으로 분류하여 해당 기능을 대체하면 된다,

 

그렇지만 그 기능이 해당 기기에서 아예 사용할 수가 없다면 crush가 발생하지 않고 해당 기능을 사용할 수 없게 try-catch문으로 예외처리를 했다.

CustomTab을 사용하지 못하는 폰에서는 WebView를 사용하게 만들어놨다.

        try{
            CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
            CustomTabsIntent customTabsIntent = builder.build();
            customTabsIntent.launchUrl(this, Uri.parse(url));
        }
        catch (Exception e){
            Log.e("err : " , e.toString());

            mWebView = (WebView) findViewById(R.id.wv_main);

            webSettings = mWebView.getSettings();
            webSettings.setJavaScriptEnabled(true);

            mWebView.setWebChromeClient(new WebChromeClient());
            mWebView.loadUrl(url);
        }

한국은 최신 기기들을 사용하니 스마트폰 테스트 때는 발생하지 않았었다. 업로드 하니 옛날버전도 다 테스트하다가 걸러진 것 같다.

 

WebView 와 CustomTab

 

Vue.JS로 개발된 프론트를 WebView로 노출하려고 했는데 페이지가 안뜨고 에러가 발생한다. 

 

그래서 Custom Tab으로 만들어보라고 해서 해봤다.

 

생각보다 간단한 코드인데 정확한 방법이 잘 검색이 안나왔다.

 

build.gradle(Module: 앱이름.app) 에 dependencies를 추가한다. 버전은 맨 아래 링크를 참조했으면 한다.

dependencies {
    ...
    implementation "androidx.browser:browser:1.3.0"
}

 

소스는 기본적으로 4줄이면 끝이다.

MainActivity.java

String url = "https://google.com/";
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, Uri.parse(url));

 

여기서 색상이라던지 작업 버튼을 구성을 하고 싶으면 바로 아래 링크를 확인하면 된다.

 

https://developer.chrome.com/docs/android/custom-tabs/integration-guide/#configure-the-color-of-the-address-bar

 

Implementation guide - Chrome Developers

Custom Tabs implementation guide

developer.chrome.com

https://developer.chrome.com/docs/android/custom-tabs/

 

Overview - Chrome Developers

An overview of Custom Tabs

developer.chrome.com

 

앱을 올리기 전에 앱 무결성이라고 서명 키를 보내야한다. 우선 안드로이드 스튜디오에서 키 생성부터 해보고 이후에 플레이 콘솔에 서명 키를 업로드 할 예정이다.

 

이 키는 굉장히 중요하기 때문에 잃어버리면 안됩니다.

잃어버리면 프로젝트에 다른 키로 서명을 하더라도 앱 업로드시 키가 달라서 업로드가 되지 않습니다. 주의하세요!

 

1. Build > Generate Signed Bundle/APK...  선택하면 아래 두 번째 사진처럼 나옵니다. 옛날에는 앱 업로드 할 때 APK로도 가능했는데 이제는 AAB(Android App Bundle)로만 올려야 합니다.

 

2. Key store path > Create new... 를 선택하면 아래처럼 나옵니다.

 

3. Key store path 를 설정합니다. 주소 선택하면서 key 이름도 같이 설정한 후 Password를 입력해줍니다.

 

4.Key 정보를 입력합니다. 여기서 Key에 대한 정보이기 때문에 중요합니다.

 

5. OK를 누르면 아래처럼 이전 화면으로 이동하고 키스토어 생성 때 입력했던 정보가 자동 입력됩니다. Key store password와 Key password가 다르니 유의 해주세요

 

이제 해당 주소에 키가 생성되어 있을겁니다. 그 키를 구글 플레이 콘솔에 올려야하지만 바로 올릴 수 없습니다.

 

6. 앱 업로드 하기 전에 서명 키 변경을 선택하고 다른 키 사용 > Java Keystore의 내보내기 및 업로드를 누르면 PEPK를 다운로드 한다.(PEPK 파일은 키 생성할때도 받을 수 있다.)

7. PEPK 파일을 Key store에 같이 둔다.

 

8. 위 이미지에 2. 코드를 복사한다. 중요한 건 keystore와 alias 이다. 여기서 자기 세팅으로 바꿔줘야한다. keystore는 자기 key 위치를 적고 끝에 파일명.확장자까지 해주면된다. alias는 아까 입력했던 별명을 써주면된다. 아래 코드를 참고하자

java -jar pepk.jar --keystore=C:\Users\94ona\Documents\Downloads\keystore\app_key.jks --alias=test --output=output.zip --include-cert --encryptionkey=eb10fe8f7c7c9df715022017b00c6471f8ba8170b13049a11e6c09ffe3056a104a3bbe4ac5a955f4ba4fe93fc8cef27558a3eb9d2a529a2092761fb833b656cd48b9de6a

 

9. 세팅이 완료됐으면 명령프롬프트 창을 열어서 keystore 위치로 간다.

cd C:\Users\94ona\Documents\Downloads\keystore

이 상태에서 세팅한 코드를 입력하면 store passwore와 alias password를 입력하면 keystore에 zip이 하나 생긴다.

 

앱 서명 환경설정에서 3. 생성된 ZIP 업로드를 하고 저장하면 끝이다.

앱스토어에 올렸는데 수정할 게 생겨서 다시 aab 파일을 업로드 했는데 버전코드는 이미 사용되었습니다. 다른 버전 코드를 사용해 보세요. 라고 나온다.

버전코드는 build.gradle (Module:앱이름.app) > android > defailtConfig >versionCode, versionName 를 변경한다.

 

나는 아래 이미지를 다 만들어야 하는 줄 알았다. 해상도별로 아이콘을 만들어야 하는 줄 알았다. 그런데 아니었고 가운데 들어갈 이미지만 필요한 거 였다.

 

앱을 어느정도 정리하고 아이콘 변경을 하러왔다.

 

1. 아이콘 이미지 준비한다. 나는 회사 이미지를 사용하지 않으니 대체 이미지를 만들었다.

참고 : 배경 없는 아이콘을 만들면 배경색도 마음대로 조절할 수 있고 크기도 더 정교하게 맞출 수 있다.

res > New > Image Asset를 선택한다.

 

2. Foreground Layer 에서 Path를 변경하여 아이콘으로 쓸 이미지를 불러온다. 불러오면 아래처럼 Preview에 미리보여주는데 각 아이콘에 맞게 Resize를 변경하여 맞춘다. 

3. Background Layer 에서 배경색을 변경한다. 위에 사진을 보면 Full Bleed Layers가 바탕색이 보인다. 그리고 이미지가 조금 작거나 크게 되면 자기 배경색이 아이콘과 조금 안 맞을 때가 있다. 그렇기 때문에 여기서 배경색을 아이콘 이미지 배경색과 맞춰주거나 아이콘의 배경색을 없애고 가져왔다면 여기서 원래 하려했던 배경색을 세팅을 해준다. 아래 이미지를 참고하자.

4. 이미지를 프로젝트에 불러왔다면 이젠 프로젝트에 적용을 시켜줘야한다.

Manifests > application > icon , roundIcon을 자신이 추가 했던 Name으로 변경한다.

앞에 포스팅을 보면서 WebView 세팅을 해주기 바란다.

 

Local HTML 파일 까지는 어떻게 열었는데 버튼 이벤트시 Native 내장 기능이 필요해졌다. 

자바스크립트와 안드로이드 네이티브를 이용하여 아래 기능을 구현해봤다.

HTML > Native : Toast 메세지

Natvie > HTML : return을 통한 데이터를 HTML 화면 출력

 

MainActvity.java

package com.saii.webview;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    public WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = (WebView) findViewById(R.id.wv_main);

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);

        mWebView.addJavascriptInterface(new Object() {
            @JavascriptInterface
            public String showToast(String keyword) {
                Toast.makeText(MainActivity.this, keyword + " 키워드 입력" , Toast.LENGTH_LONG).show();
                String param1 = keyword + " return android - Saii";
                return param1;
            }
        }, "Saii");
        mWebView.loadUrl("file:///android_asset/index.html");

    }
}

참고

https://github.com/saii42/android/tree/main/example/WebView

 

GitHub - saii42/android: android

android. Contribute to saii42/android development by creating an account on GitHub.

github.com

https://developer.android.com/guide/webapps/webview#UsingJavaScript

 

WebView에서 웹 앱 빌드  |  Web Apps  |  Android Developers

You can test your app against unreleased future versions of WebView. Get started now!. WebView에서 웹 앱 빌드 웹 애플리케이션 또는 웹페이지만 클라이언트 애플리케이션의 일부로 제공하려는 경우 WebView를 사용하면

developer.android.com

 

 

 

Splash 이후 뭔가 홍보나 광고 가이드 화면을 ViewPager를 이용하여 Fragment를 연결시켜 스와이프 제스처가 가능한 화면을 만들어 볼 거다. 그리고 스킵과 메인화면으로 넘어가는 버튼을 만들었다. 생각해보면 엄청 많이 필요한 것 같아서 적어봤다.

 

1. 우선 화면에 사용할 이미지를 먼저 drawable 폴더에 넣어준다.

(나는 화면 구분을 위해 대충 3개 만들었다.)


2. 처음 생성된 main 제외하고 fragment 3개 정도만 만들자. 이미지 참조


3. Fragment는 이미지 뷰와 텍스트뷰 또는 버튼뷰를 배치한다. Activity는 ViewPager2를 배치한다.

 

fragment_guide1.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".GuideFragment1">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_height="match_parent"
        android:layout_width="match_parent">

        <ImageView
            android:id="@+id/iv_guide1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toTopOf="@+id/tv_skip1"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.522"
            app:srcCompat="@drawable/img_guide1"
            tools:ignore="ContentDescription" />

        <TextView
            android:id="@+id/tv_skip1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="56dp"
            android:text="건너뛰기 >"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

fragment_guide2.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".GuideFragment2">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_height="match_parent"
        android:layout_width="match_parent">

        <ImageView
            android:id="@+id/iv_guide2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toTopOf="@+id/tv_skip2"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.522"
            app:srcCompat="@drawable/img_guide2"
            tools:ignore="ContentDescription" />
        <TextView
            android:id="@+id/tv_skip2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="56dp"
            android:text="건너뛰기 >"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

fragment_ad1.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".AdFragment1">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_height="match_parent"
        android:layout_width="match_parent">

        <ImageView
            android:id="@+id/iv_ad1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toTopOf="@+id/btn_skip3"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/img_ad1" />

        <Button
            android:id="@+id/btn_skip3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="4dp"
            android:text="시작하기 >"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintStart_toStartOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

프리뷰로 본 Fragment 화면이다. 

activity_guide.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".GuideActivity">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vp_guide"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

</androidx.constraintlayout.widget.ConstraintLayout>

 


3. ViewPager의 Adapter를 만들어준다.

ViewPagerAdapter.java

package com.saii.viewpager2_guide;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;

class ViewPagerAdapter extends FragmentStateAdapter {

   public int mCount;
   public ViewPagerAdapter(FragmentActivity fa, int count) {
      super(fa);
      mCount = count;
   }

   public Fragment createFragment(int position) {
      int index = getRealPosition(position);
      if(index==0) return new GuideFragment1();
      else if(index==1) return new GuideFragment2();
      else return new AdFragment1();
   }
   @Override
   public int getItemCount() {
      return 3;
   }
   public int getRealPosition(int position) { return position % mCount; }

}

4. MainActivity.java에서 ViewPager와 Adapter를 연결해준다.

MainActivity.java

package com.saii.viewpager2_guide;

import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private ViewPager2 mPager;
    private FragmentStateAdapter pagerAdapter;
    private final int num_page = 3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mPager = findViewById(R.id.vp_guide);
        pagerAdapter = new ViewPagerAdapter(this, num_page);
        mPager.setAdapter(pagerAdapter);

        mPager.setCurrentItem(1); //시작 지점
        mPager.setOffscreenPageLimit(num_page); //최대 페이지 수

        mPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                super.onPageScrolled(position, positionOffset, positionOffsetPixels);
                if (positionOffsetPixels == 0) {
                    mPager.setCurrentItem(position);
                }
            }

            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
            }
        });
    }
}

5. 각 Fragment에 이벤트를 정의합니다. Fragment에는 메인 화면으로 갈 수 있는 이벤트를 코딩했습니다. 클릭 이벤트를 커스텀 하고 싶다면 onClick 안에 다른 코딩을 하시면 됩니다. 간혹 Fragment에서 뷰가 인식이 안된다는 사람이 있는데 그 부분은 나중에 Fragment를 참조하면 될 것 같다. 

GuideFragment1.java

package com.saii.viewpager2_guide;

import android.content.Intent;
import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;


public class GuideFragment1 extends Fragment {

    private TextView tvSkip1;
    private View view;

    @Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_guide1, container, false);

        tvSkip1 = view.findViewById(R.id.tv_skip1);
        tvSkip1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), MainActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                startActivity(intent);
                getActivity().finish();
            }
        });

        return view;
    }
}

GuideFragment2.java

package com.saii.viewpager2_guide;

import android.content.Intent;
import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class GuideFragment2 extends Fragment {

    private TextView tvSkip2;
    private View view;

    @Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_guide2, container, false);

        tvSkip2 = view.findViewById(R.id.tv_skip2);
        tvSkip2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), MainActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                startActivity(intent);
                getActivity().finish();
            }
        });

        return view;
    }
}

AdFragment1.java

package com.saii.viewpager2_guide;

import android.content.Intent;
import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;


public class AdFragment1 extends Fragment {

    private Button btnSkip3;
    private View view;

    @Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_ad1, container, false);

        btnSkip3 = view.findViewById(R.id.btn_skip3);
        btnSkip3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), MainActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                startActivity(intent);
                getActivity().finish();
            }
        });
        return view;
    }
}

 

 

참조

https://github.com/saii42/android/tree/main/example/Splash

 

GitHub - saii42/android: android

android. Contribute to saii42/android development by creating an account on GitHub.

github.com

 

어플에 시작화면을 해볼 것이다. 나는 이미지 작업이 안되니 간단하게 해볼 것이다. 

안드로이드 12 에서 Splash screen(windowSplashScreenBackground)를 해볼 예정이다.

 

Splash Activity를 Delay 하는 방식이다. (Delay를 하지않아도 Splash가 가능하다.)

 

1. Splash로 사용할 이미지를 drawable 폴더에 추가한다.


2. Splash , Main 화면을 만든다.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

activity_splash.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SplashActivity">

</androidx.constraintlayout.widget.ConstraintLayout>


3. 화면을 추가했으니 manifest에 수정해줘야한다.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.saii.splash">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".SplashActivity"
            android:theme="@style/SplashTheme"
            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">
        </activity>
    </application>
</manifest>

4. 스타일에 테마를 추가한다.

style.xml

<resources>
... 
    <style name="SplashTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="android:windowBackground">@drawable/xxx</item> //xxx <= drawable 폴더에 추가한 이미지 이름
    </style>
</resources>

5. java 파일에 delay 코드만 추가하면 된다.

SplashActvity.java

package com.saii.splash;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;

public class SplashActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        gotoMain(1);  // 파라미터 만큼 delay가 된다.

    }

    private void gotoMain(int sec) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent(getApplicationContext(), MainActivity.class);
                startActivity(intent);
                finish();
            }
        }, 1000 * sec);
    }
}

 

 


참조

https://github.com/saii42/android/tree/main/example/Splash

 

GitHub - saii42/android: android

android. Contribute to saii42/android development by creating an account on GitHub.

github.com

https://developer.android.com/guide/topics/ui/splash-screen#java

 

Splash screens  |  Android Developers

Splash screens Important: If you have previously implemented a custom splash screen in Android 11 or lower, you'll need to migrate your app to the SplashScreen API to ensure that it displays correctly in Android 12 and higher. For instructions, see Migrate

developer.android.com

 

+ Recent posts