App Intro c использованием видео из YouTube

  • Tutorial
Привет, друзья! Некоторое время назад я писал статью про App Intro (Onboarding Experience), с помощью которого мы можем дать юзеру нашего приложения ознакомительный материал при первом запуске.

Теперь же я хочу рассказать и показать, как можно реализовать App Intro c помощью видео из YouTube.
Допустим, что вы делаете супер-мега крутой проект и у вас есть его промо-ролик. Наша цель показать это видео внутри вашего приложения, как ознакомительное и дать понять пользователю, что он сделал правильный выбор.






Intro (вводное информационное активити, запускающее при первом старте приложения на девайсе) на базе видео с YouTube может быть весьма полезно, чтобы показать юзеру все фичи в реальном видео. Или это может быть рекламный ролик — не столько фичи, сколько реклама того какой апп интересный, полезный, прикольный и т.п.

Итак приступим к реалзации:

1) Для начала нам нужно создать проект и получить API Key в Google Developer Console:

a) создаем проект и активируем YouTube Data API:



b) Создаем API Key для Android приложения: даем название (произвольное), пакет своего проекта и генерируем SHA-1



После этих шагов вы получите API Key, такого плана: AIzaSyCKQSxрJFAHFHj9r2wfwfqkagkhFFa

Сохраните его, мы будем его использовать.

2) Создаем новый проект в Android Studio:

a) добавляем в strings.xml:

    <string name="intro_header">Introduction</string>
    <string name="skip_intro">Skip Intro</string>
    <string name="error_player">Error initializing Youtube player: %1$s</string>


b) в colors.xml:

<!-- Intro Youtube video -->
    <color name="intro_skip_normal">#9e9e9e</color>
    <color name="intro_skip_active">#616161</color>


c) в dimens.xml:

<!-- Additional margins including ones for Intro Youtube video -->
    <dimen name="middle_margin">8dp</dimen>
    <dimen name="bottom_text_margin">40dp</dimen>


d) создадим директорию color и в ней файл intro_text_link.xml (будем применять этот стиль в layouts):

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
        android:color="@color/intro_skip_active" />
    <item android:state_focused="true"
        android:color="@color/intro_skip_active" />
    <item android:color="@color/intro_skip_normal" /> <!-- default -->
</selector>


На данном этапе нам нужно подключить библиотеку для просмотра видео-роликов.
Скачиваем архив библиотеки YouTube по этой ссылке.

Далее, нужно скопировать и вставить файл YouTubeAndroidPlayerApi.jar в app/libs (в студии переключиться на Project), и нажать кнопку Sync на панеле инструментов (или в меню: Tools > Android > Sync Project with Gradle Files)

3) Теперь создадим Java класс Config, в котором будем хранить Google API Key и id для видео, которое мы будем использовать в нашем Intro (в URL следует после "?v=", например, для видео www.youtube.com/watch?v=aScEqSidNf8 id будет aScEqSidNf8):

public class Config {

    //Google API Key
    static final String API_KEY = "AIzaSyCKQSxрJFAHFHj9r2wfwfqkagkhFFa";

    //YouTube video id for intro
    static final String YOUTUBE_INTRO_ID = "aScEqSidNf8";
}


4) Создадим теперь xml файлы внутри папке drawable, которые будут отвечать за background нашего Intro и за скругление углов:

a) intro_gradient.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="@color/colorPrimaryDark"
        android:centerColor="@color/colorPrimary"
        android:endColor="@color/colorPrimary"
        android:angle="270" />
</shape>


b) intro_rounded_corners.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape android:shape="rectangle" >
            <solid android:color="@android:color/white" />
            <corners android:radius="8dp" />
        </shape>
    </item>
</layer-list>


5) Теперь создадим layout файл activity_intro.xml для нашего Intro (вертикальная ориентация):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@drawable/intro_gradient">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:gravity="center_horizontal"
    android:layout_marginStart="@dimen/activity_horizontal_margin"
    android:layout_marginEnd="@dimen/activity_horizontal_margin"
    android:orientation="vertical"
    android:background="@drawable/intro_rounded_corner">

    <TextView
        android:text="@string/intro_header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Headline" />

    <com.google.android.youtube.player.YouTubePlayerView
        android:id="@+id/youtube_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/middle_margin" />

    <ImageView
        android:src="@mipmap/ic_launcher"
        android:contentDescription="@string/app_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/middle_margin" />

    <TextView
        android:text="@string/app_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/bottom_text_margin"
        android:textAppearance="@style/TextAppearance.AppCompat.Title" />

    <TextView
        android:id="@+id/skip_intro"
        android:text="@string/skip_intro"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/activity_vertical_margin"
        android:textColor="@color/intro_text_link" />
</LinearLayout>
</LinearLayout>



И для горизонтальной ориентации (создаем директорию layout-land, в которую помещаем идентичный файл activity_intro.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@drawable/intro_gradient">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="@drawable/intro_rounded_corner"
    android:layout_gravity="center"
    android:gravity="center_vertical"
    android:baselineAligned="false"
    android:layout_marginStart="@dimen/activity_horizontal_margin"
    android:layout_marginEnd="@dimen/activity_horizontal_margin">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical"
        android:layout_marginTop="@dimen/activity_vertical_margin">

        <ImageView
            android:src="@mipmap/ic_launcher"
            android:contentDescription="@string/app_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="@dimen/middle_margin" />

        <TextView
            android:text="@string/app_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="@dimen/bottom_text_margin"
            android:textAppearance="@style/TextAppearance.AppCompat.Title" />

        <TextView
            android:id="@+id/skip_intro"
            android:text="@string/skip_intro"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="@dimen/activity_vertical_margin"
            android:textColor="@color/intro_text_link" />
    </LinearLayout>

    <com.google.android.youtube.player.YouTubePlayerView
        android:id="@+id/youtube_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="3" />
</LinearLayout>
</LinearLayout>


6) Создаем класс YouTubeFailureRecoveryActivity. Выносим его в отдельный класс, поскольку в случае наличия YouTube-функционала в других частях приложение, используется этот же класс:

public abstract class YouTubeFailureRecoveryActivity extends YouTubeBaseActivity implements
        YouTubePlayer.OnInitializedListener {

    private static final int RECOVERY_DIALOG_REQUEST = 1;

    @Override
    public void onInitializationFailure(YouTubePlayer.Provider provider,
                                        YouTubeInitializationResult errorReason) {
        if (errorReason.isUserRecoverableError()) {
            errorReason.getErrorDialog(this, RECOVERY_DIALOG_REQUEST).show();
        } else {
            String errorMessage = String.format(getString(R.string.error_player), errorReason.toString());
            Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == RECOVERY_DIALOG_REQUEST) {
            // Retry initialization if user performed a recovery action
            getYouTubePlayerProvider().initialize(Config.API_KEY, this);
        }
    }

    protected abstract YouTubePlayer.Provider getYouTubePlayerProvider();

}


7) Создаем IntroActivity.java:

public class IntroActivity extends YouTubeFailureRecoveryActivity {

    YouTubePlayerView youTubeView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_intro);

        youTubeView = (YouTubePlayerView) findViewById(R.id.youtube_view);
        youTubeView.initialize(Config.API_KEY, this);

        // Закрываем Intro при клике на ссылку Skip Intro
        TextView skipIntro = (TextView) findViewById(R.id.skip_intro);
        skipIntro.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                /* Чтобы Intro можно было посмотреть позже, например, из главного активити
                 * и чтобы это активити не открывалось повторно при закрытии Intro, добавим
                 * экстра к интенту вызывающего активити: intent.putExtra(EXTRA_TEXT, "MainActivity").
                 * А здесь проверяем: если есть экстра - значит Intro было запущено из
                 * активити - тогда при клике на Skip Intro просто закрываем Intro.
								 * А если нет экстра - значит Intro было запущено при первом открытии аппа -
                 * сначала открываем главное активити, и затем закрываем Intro. */
                Intent intent = getIntent();
                String extra = intent.getStringExtra(MainActivity.EXTRA_TEXT);
                if (extra == null) {
                    intent.setClass(getApplicationContext(), MainActivity.class);
                    startActivity(intent);
                }
                finish();
            }
        });
    }


    @Override
    protected YouTubePlayer.Provider getYouTubePlayerProvider() {
        return youTubeView;
    }

    @Override
    public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
        if (!b) {
            youTubePlayer.cueVideo(Config.YOUTUBE_INTRO_ID);
        }
    }
}



Последним шагом в реализации данного функционала остается добавление permissions в Manifest и декларация IntroActivity:

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


Так выглядит результат проделанной работы в вертикальной и горизонтальной ориентации:



Я постарался в этой статье рассказать полезную вещь, которая надеюсь пригодится вам для создания интересных проектов и будет полезна. Если у вас остались вопросы, то попробую ответить на них.
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 5

    +3
    А если устройство offline — вывалится стандартная ошибка отсутствия сети? Есть ли план Б? Или пример следует понимать именно как пример проигрыша youtube ролика?
      0
      тут все стандартно. Если нет сети, то будет в окне с роликом написанно: «Нет подключения к сети. Повторите попытку». Можно реализовать проверку на internet connection, если есть — показывать Intro, а если нет — показывать когда будет.
      +1
      А Youtube рекламу не вставит перед роликом?
      А после ролика не появятся «похожие видео» про собачек?
        +1
        Если вы используете свое видео и у вас нет монетизации — не вставит. Про собачек ничего не появится, если вы читали статью, то мы жестко указываем id одного видео, поэтому других видео — не будет.
        0
        Важный момент: для корректной обработки поворота экрана в манифесте необходимо добавить
        android:configChanges="keyboardHidden|orientation|screenSize"
        

        Only users with full accounts can post comments. Log in, please.