콘솔로 이동

개인 콘텐츠 색인 생성 사용 설정

앱에서 개인 콘텐츠 색인을 생성하면 사용자의 계정에 연결된 콘텐츠를 Google 앱 검색결과로 볼 수 있습니다. 사용자는 추천 검색어 및 개인정보 검색결과에서 자신의 기기에서만 개인 콘텐츠를 볼 수 있습니다.

예를 들어 사용자가 '맛 좋은 닭고기 레시피'를 검색하면 사용자가 레시피 앱에서 닭고기 레시피에 추가한 메모가 개인정보 검색결과 탭에 포함됩니다.

앱에 개인 콘텐츠가 포함되지 않은 경우 이 단계를 건너뛰고 사용자 작업 기록으로 진행할 수 있습니다.

시작하기 전에 앱 콘텐츠에 대한 링크를 지원하고 앱에 앱 색인 생성 라이브러리를 추가했는지 확인합니다.

색인 설정 및 객체 추가

JobIntentService를 확장하는 클래스를 만듭니다. 이 문서에서 설명하는 구현 방법은 JobIntentService 클래스를 활용하여 기기의 색인 업데이트 작업을 대기열에 두는 것이지만 다른 클래스를 사용해 작업을 예약할 수도 있습니다. JobIntentService 클래스를 사용하여 구현하는 경우에는 프로젝트의 build.gradle 파일에 Android 지원 라이브러리도 추가해야 합니다.

그런 다음 같은 클래스에 Indexable 객체를 만들어 앱의 개인 콘텐츠 색인에 항목을 포함시킵니다.

결과 유형

앱 색인 생성을 사용하면 두 가지 방법으로 결과를 표시할 수 있습니다.

  • 텍스트 전용: Google 검색은 색인이 생성된 콘텐츠를 텍스트 결과로 표시합니다.
  • 슬라이스: Google 검색은 앱의 UI 템플릿인 슬라이스를 사용하여 동적 대화형 검색결과를 제공합니다.

앱에 가장 적합한 결과 유형을 선택할 수 있습니다. 텍스트 전용 결과는 구현하기에 덜 복잡하고 슬라이스는 보다 다양한 사용자 환경을 제공합니다.

샘플 구현

텍스트 전용 결과

자바
Android

public class AppIndexingUpdateService extends JobIntentService {

    // Job-ID must be unique across your whole app.
    private static final int UNIQUE_JOB_ID = 42;

    public static void enqueueWork(Context context) {
        enqueueWork(context, AppIndexingUpdateService.class, UNIQUE_JOB_ID, new Intent());
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        // TODO Insert your Indexable objects — for example, the recipe notes look as follows:

        ArrayList<Indexable> indexableNotes = new ArrayList<>();

        for (Recipe recipe : getAllRecipes()) {
            Note note = recipe.getNote();
            if (note != null) {
                Indexable noteToIndex = Indexables.noteDigitalDocumentBuilder()
                        .setName(recipe.getTitle() + " Note")
                        .setText(note.getText())
                        .setUrl(recipe.getNoteUrl())
                        .build();

                indexableNotes.add(noteToIndex);
            }
        }

        if (indexableNotes.size() > 0) {
            Indexable[] notesArr = new Indexable[indexableNotes.size()];
            notesArr = indexableNotes.toArray(notesArr);

            // batch insert indexable notes into index
            FirebaseAppIndex.getInstance().update(notesArr);
        }
    }

    // ...
}

Kotlin
Android

class AppIndexingUpdateService : JobIntentService() {

    companion object {

        // Job-ID must be unique across your whole app.
        private const val UNIQUE_JOB_ID = 42

        fun enqueueWork(context: Context) {
            JobIntentService.enqueueWork(context, AppIndexingUpdateService::class.java, UNIQUE_JOB_ID, Intent())
        }
    }

    override fun onHandleWork(intent: Intent) {
        // TODO Insert your Indexable objects — for example, the recipe notes look as follows:

        val indexableNotes = arrayListOf<Indexable>()

        for (recipe in getAllRecipes()) {
            val note = recipe.note
            if (note != null) {
                val noteToIndex = Indexables.noteDigitalDocumentBuilder()
                        .setName(recipe.title + " Note")
                        .setText(note.text)
                        .setUrl(recipe.noteUrl)
                        .build()

                indexableNotes.add(noteToIndex)
            }
        }

        if (indexableNotes.size > 0) {
            val notesArr: Array<Indexable> = indexableNotes.toTypedArray()

            // batch insert indexable notes into index
            FirebaseAppIndex.getInstance().update(*notesArr)
        }
    }

    // ...
}
슬라이스 결과

슬라이스를 사용하면 Google 검색어에 대한 응답으로 표시할 앱의 일부를 지정할 수 있습니다. Indexables 콘텐츠에 대한 UI 역할을 하기 때문에 Indexable에 각 슬라이스를 직접 매핑해야 합니다. 다음 단계에 따라 앱에 대한 슬라이스 사용 결과를 생성하세요.

  1. 슬라이스 시작 가이드의 안내에 따라 앱에 슬라이스를 추가합니다.
  2. 슬라이스 메타데이터 및 리스너가 있는 Indexables를 추가합니다.
package com.example.myapp;

import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
import com.google.firebase.appindexing.builders.Indexables;
import com.google.firebase.appindexing.FirebaseAppIndex;
import com.google.firebase.appindexing.Indexable;
import java.util.ArrayList;

public class AppIndexingUpdateService extends JobIntentService {
  // Job-ID must be unique across your whole app.
  private static final int UNIQUE_JOB_ID = 42;

  public static void enqueueWork(Context context) {
    enqueueWork(context, AppIndexingUpdateService.class, UNIQUE_JOB_ID, new Intent());
  }

  @Override
  protected void onHandleWork(@NonNull Intent intent) {
    // TODO Insert your Indexable objects — for example, the recipe notes look as follows:

    ArrayList<Indexable> indexableNotes = new ArrayList<>();

    for (Recipe recipe : getAllRecipes()) {
        Note note = recipe.getNote();
        if (note != null) {
            Indexable noteToIndex = Indexables.noteDigitalDocumentBuilder()
                    .setName(recipe.getTitle() + " Note")
                    .setText(note.getText())
                    .setUrl(recipe.getNoteUrl())
                    .setMetadata(
                      new Indexable.Metadata.Builder().setSliceUri(
                        Uri.parse("content://com.example.myapp.sliceprovider/note?id=" +
                                  recipe.getNoteId())
                    ))
                    .build();

            indexableNotes.add(noteToIndex);
        }
    }

    if (indexableNotes.size() > 0) {
        Indexable[] notesArr = new Indexable[indexableNotes.size()];
        notesArr = indexableNotes.toArray(notesArr);

        // batch insert indexable notes into index
        FirebaseAppIndex.getInstance().update(notesArr)
                        .addOnSuccessListener(unused -> {
                          Log.d("RecipeApp", "Update succeeded!");
                        })
                        .addOnFailureListener(exception -> {
                          Log.d("RecipeApp", "Update failed: " + exception);
                        });
    }
  }
}

개인 콘텐츠 색인에 포함할 정보

다음과 같은 콘텐츠 유형의 Indexable 객체를 정의합니다.

  • 메시지, 사진, 문서 등의 사용자별 콘텐츠
  • 즐겨찾기 혹은 사용자가 자주 액세스할만한 콘텐츠 등 사용자에게 중요한 콘텐츠. 북마크에 추가했거나 오프라인 사용 설정한 문서나 노래를 예로 들 수 있습니다.
  • 단순히 앱에서 액세스한 것이 아니라 앱 안에서 생성한 콘텐츠. 예를 들어 휴대전화의 주소록에서 가져오지 않고 사용자가 앱에서 직접 작성하여 저장한 연락처가 여기에 해당합니다.

앱에 broadcast receiver 추가

Google Play 서비스는 기기의 색인을 업데이트하라는 요청을 주기적으로 앱에 전송합니다. 이렇게 하면 기기의 색인에 앱의 최신 콘텐츠를 포함할 수 있습니다. BroadcastReceiver 클래스는 이 요청을 받고 JobIntentService를 트리거하여 색인 생성 작업을 처리합니다. 아래는 이전 단계의 AppIndexingUpdateService 클래스를 사용한 예입니다.

자바
Android

/** Receives broadcast for App Indexing Update. */
public class AppIndexingUpdateReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null
                && FirebaseAppIndex.ACTION_UPDATE_INDEX.equals(intent.getAction())) {
            // Schedule the job to be run in the background.
            AppIndexingUpdateService.enqueueWork(context);
        }
    }

}

Kotlin
Android

/** Receives broadcast for App Indexing Update. */
class AppIndexingUpdateReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent?) {
        if (intent != null && FirebaseAppIndex.ACTION_UPDATE_INDEX == intent.action) {
            // Schedule the job to be run in the background.
            AppIndexingUpdateService.enqueueWork(context)
        }
    }
}

색인 생성 및 새로고침

다음 3가지 상황에서는 Google Play 서비스가 앱 색인 생성 서비스를 호출하여 사용자의 개인 콘텐츠로 기기의 색인을 업데이트할 수 있도록 허용해야 합니다.

  • 기기에 앱이 설치될 때
  • 앱의 기존 버전이 개인 콘텐츠 색인을 지원하는 버전으로 업데이트된 경우
  • 색인에 추가된 콘텐츠의 변경을 정확히 반영하여 원활한 사용자 환경을 제공하기 위한 주기적 호출

또한 어떠한 이유로 인해 기기에서 색인이 손실된 경우(예: 색인이 손상된 경우) 색인 업데이트를 호출하면 색인이 다시 채워집니다.

AndroidManifest.xml 파일에서 Google Play 서비스의 호출을 수신하여 색인을 업데이트할 수 있도록 BroadcastReceiver를 등록합니다. 다음은 JobIntentService 클래스를 사용하여 색인 생성 업데이트를 예약하는 예입니다.

<!-- Register the BroadcastReceiver -->
<receiver
    android:name=".AppIndexingUpdateReceiver"
    android:exported="true"
    android:permission="com.google.android.gms.permission.APPINDEXING">
    <intent-filter>
        <action android:name="com.google.firebase.appindexing.UPDATE_INDEX" />
    </intent-filter>
</receiver>

<!-- Grant the AppIndexingUpdateService permission and enable it to run after being triggered -->
<service
    android:name=".AppIndexingUpdateService"
    android:permission="android.permission.BIND_JOB_SERVICE" />

색인 업데이트

사용자가 개인 콘텐츠를 추가, 업데이트 또는 삭제하면 기기의 색인에 변경사항이 반영되어야 합니다. 다음 코드를 추가하여 색인의 콘텐츠를 업데이트합니다.

텍스트 전용 업데이트

자바
Android

public void indexNote(Recipe recipe) {
    Note note = recipe.getNote();
    Indexable noteToIndex = Indexables.noteDigitalDocumentBuilder()
            .setName(recipe.getTitle())
            .setText(note.getText())
            .setUrl(recipe.getNoteUrl())
            .build();

    Task<Void> task = FirebaseAppIndex.getInstance().update(noteToIndex);
    // ...
}

Kotlin
Android

fun indexNote(recipe: Recipe) {
    val note = recipe.note
    val noteToIndex = Indexables.noteDigitalDocumentBuilder()
            .setName(recipe.title)
            .setText(note!!.text)
            .setUrl(recipe.noteUrl)
            .build()

    val task = FirebaseAppIndex.getInstance().update(noteToIndex)
    // ...
}
슬라이스 업데이트

Firebase 앱 색인 생성은 색인을 생성할 때 슬라이스 콘텐츠를 가져와 저장하고 쿼리할 때 슬라이스 스냅샷을 표시합니다. 슬라이스 콘텐츠가 색인 생성과 쿼리 실행 사이에 변경되면 해당 스냅샷은 사용자에게 오해를 일으키거나 혼동을 줄 수 있습니다. 이 문제를 방지하려면 슬라이스를 업데이트하고 동시에 색인 생성 가능한 객체에 대해 다시 색인을 생성하여 Firebase 앱 색인 생성에 항상 최신 슬라이스 콘텐츠를 포함하도록 합니다.

private void indexNote() {
  Note note = mRecipe.getNote();
  Indexable noteToIndex = Indexables.noteDigitalDocumentBuilder()
          .setName(mRecipe.getTitle())
          .setText(note.getText())
          .setUrl(mRecipe.getNoteUrl())
          .setKeywords("recipe", "cooking")
          .setMetadata(
              new Indexable.Metadata.Builder().setSliceUri(
              Uri.parse("content://com.example.myapp.sliceprovider/note?id=" + note.getNoteId())))
          .build();

  Task<Void> task = FirebaseAppIndex.getInstance().update(noteToIndex);
   ...
}
삭제

삭제할 항목을 식별하려면 항목의 URL을 사용합니다. 해당 항목에 대한 앱의 삭제 또는 제거 함수에 다음 줄을 추가하세요.

자바
Android

// Deletes or removes the corresponding notes from index.
String noteUrl = recipe.getNoteUrl();
FirebaseAppIndex.getInstance().remove(noteUrl);

Kotlin
Android

// Deletes or removes the corresponding notes from index.
val noteUrl = recipe.noteUrl
FirebaseAppIndex.getInstance().remove(noteUrl)

로그아웃 시 색인 삭제

사용자가 앱에서 로그아웃하여 로그아웃 이벤트가 발생할 때 기기의 색인을 삭제합니다. 사용자가 다시 로그인할 때 기기의 색인을 다시 채우려면 AppIndexingService를 사용하여 색인을 생성하고 새로 고치는 호출을 포함시킵니다.

사용자가 앱에서 로그아웃할 때 기기의 색인을 삭제하려면 앱에 다음 코드를 추가합니다.

자바
Android

FirebaseAppIndex.getInstance().removeAll();

Kotlin
Android

FirebaseAppIndex.getInstance().removeAll()

다음: 사용자 작업 로깅