Google API にアクセスする

Google Play 開発者サービス(Google ログインや ML Kit など)を利用する SDK の API を呼び出すには、まず API クライアント オブジェクトのインスタンスを作成する必要があります。これらのオブジェクトは、Google Play 開発者サービスへの接続を自動的に管理します。接続が利用可能になると、各 API クライアント オブジェクトがリクエストを順番に実行します。それ以外の場合、クライアント オブジェクトはリクエストをキューに追加します。ドキュメントに特に記載がない限り、クライアント オブジェクトの作成は簡単です。API メソッドを呼び出すたびに新しい API クライアントを作成しても問題ありません。

このガイドでは、Google Play サービスが提供する SDK に対して API 呼び出しを行う方法について説明します。認証を必要としないサービスと認証を必要とするサービスにアクセスする方法も説明します。

使ってみる

始めに、Google Play 開発者サービスをセットアップする方法のガイドに記載されているように、必要なツールと依存関係をアプリ プロジェクトに追加します。

認可が不要な場合のアクセス

API 認可を必要としないサービスにアクセスするには、サービスのクライアント オブジェクトのインスタンスを取得し、現在の Context または現在の Activity を渡します。API 呼び出しが実行される前に、必要に応じて Google Play 開発者サービスをアップグレードするようユーザーに求めるメッセージが表示されます。

たとえば、Android の Fused Location Provider を使用してデバイスの直近の位置情報を取得するには、次のコード スニペットに示すロジックを追加します。

Kotlin

// Code required for requesting location permissions omitted for brevity.
val client = LocationServices.getFusedLocationProviderClient(this)

// Get the last known location. In some rare situations, this can be null.
client.lastLocation.addOnSuccessListener { location : Location? ->
    location?.let {
        // Logic to handle location object.
    }
}

Java

// Code required for requesting location permissions omitted for brevity.
FusedLocationProviderClient client =
        LocationServices.getFusedLocationProviderClient(this);

// Get the last known location. In some rare situations, this can be null.
client.getLastLocation()
        .addOnSuccessListener(this, location -> {
            if (location != null) {
                // Logic to handle location object.
            }
        });

認証が必要な場合のアクセス

ユーザーの承認が必要なサービスにアクセスするには、次の操作を行います。

  1. ユーザーのログインを行う
  2. サービスに必要なスコープへのアクセス権をリクエストします。
  3. サービスのクライアント オブジェクトのインスタンスを取得し、Context オブジェクトまたは Activity オブジェクトに加えて、ユーザーの GoogleSignInAccount オブジェクトを渡します。

次の例は、Google Fit API を使用してユーザーの 1 日の歩数を読み取るコードを実装しています。完全なプロジェクトのコンテキストで同様の実装を確認するには、GitHub で BasicHistoryApiKotlin アプリのメイン アクティビティをご覧ください。

Kotlin

class FitFragment : Fragment() {
    private val fitnessOptions: FitnessOptions by lazy {
        FitnessOptions.builder()
            .addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
            .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
            .build()
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        fitSignIn()
    }

    /*
     * Checks whether the user is signed in. If so, executes the specified
     * function. If the user is not signed in, initiates the sign-in flow,
     * specifying the function to execute after the user signs in.
     */
    private fun fitSignIn() {
        if (oAuthPermissionsApproved()) {
            readDailySteps()
        } else {
            GoogleSignIn.requestPermissions(
                this,
                SIGN_IN_REQUEST_CODE,
                getGoogleAccount(),
                fitnessOptions
            )
        }
    }

    private fun oAuthPermissionsApproved() =
        GoogleSignIn.hasPermissions(getGoogleAccount(), fitnessOptions)

    /*
     * Gets a Google account for use in creating the fitness client. This is
     * achieved by either using the last signed-in account, or if necessary,
     * prompting the user to sign in. It's better to use the
     * getAccountForExtension() method instead of the getLastSignedInAccount()
     * method because the latter can return null if there has been no sign in
     * before.
     */
    private fun getGoogleAccount(): GoogleSignInAccount =
        GoogleSignIn.getAccountForExtension(requireContext(), fitnessOptions)

    /*
     * Handles the callback from the OAuth sign in flow, executing the function
     * after sign-in is complete.
     */
    override fun onActivityResult(
            requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (resultCode) {
            RESULT_OK -> {
                readDailySteps()
            }
            else -> {
                // Handle error.
            }
        }
    }

    /*
     * Reads the current daily step total.
     */
    private fun readDailySteps() {
        Fitness.getHistoryClient(requireContext(), getGoogleAccount())
            .readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
            .addOnSuccessListener { dataSet ->
                val total = when {
                    dataSet.isEmpty -> 0
                    else -> dataSet.dataPoints.first()
                            .getValue(Field.FIELD_STEPS).asInt()
                }

                Log.i(TAG, "Total steps: $total")
            }
            .addOnFailureListener { e ->
                Log.w(TAG, "There was a problem getting the step count.", e)
            }
    }

    companion object {
        const val SIGN_IN_REQUEST_CODE = 1001
    }
}

Java

public class FitFragment extends Fragment {
    private final FitnessOptions fitnessOptions = FitnessOptions.builder()
            .addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
            .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
            .build();

    @Override
    public void onViewCreated(
            @NotNull View view, @Nullable Bundle savedInstanceState) {
        fitSignIn();
    }

    /*
     * Checks whether the user is signed in. If so, executes the specified
     * function. If the user is not signed in, initiates the sign-in flow,
     * specifying the function to execute after the user signs in.
     */
    private void fitSignIn() {
        if (oAuthPermissionsApproved()) {
            readDailySteps();
        } else {
            GoogleSignIn.requestPermissions(this, SIGN_IN_REQUEST_CODE,
                    getGoogleAccount(), fitnessOptions);
        }
    }

    private boolean oAuthPermissionsApproved() {
        return GoogleSignIn.hasPermissions(getGoogleAccount(), fitnessOptions);
    }

    /*
     * Gets a Google account for use in creating the fitness client. This is
     * achieved by either using the last signed-in account, or if necessary,
     * prompting the user to sign in. It's better to use the
     * getAccountForExtension() method instead of the getLastSignedInAccount()
     * method because the latter can return null if there has been no sign in
     * before.
     */
    private GoogleSignInAccount getGoogleAccount() {
        return GoogleSignIn.getAccountForExtension(
                requireContext(), fitnessOptions);
    }

    /*
     * Handles the callback from the OAuth sign in flow, executing the function
     * after sign-in is complete.
     */
    @Override
    public void onActivityResult(
            int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            readDailySteps();
        } else {
            // Handle error.
        }
    }

    /*
     * Reads the current daily step total.
     */
    private void readDailySteps() {
        AtomicInteger total = new AtomicInteger();
        Fitness.getHistoryClient(requireContext(), getGoogleAccount())
                .readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
                .addOnSuccessListener(dataSet -> {
                    if (!dataSet.isEmpty())
                        total.set(Integer.parseInt(dataSet.getDataPoints()
                                .get(0).getValue(FIELD_STEPS).toString()));
                        Log.i(TAG, "Total steps: $total");
                })
                .addOnFailureListener(e -> {
                    Log.w(TAG, "There was a problem getting the step count.", e);
                });
    }

    private static final int SIGN_IN_REQUEST_CODE = 1001;
}

API の可用性を確認する

Google Play 開発者サービスの API に依存する機能をアプリで有効にする前に、デバイスで API が利用可能かどうかを確認するコードを追加します。これを行うには、checkApiAvailability() を呼び出します。

次のコード スニペットは、統合位置情報プロバイダの可用性を確認する方法を示しています。

Kotlin

fun getLastLocationIfApiAvailable(context: Context?): Task<Location>? {
    val client = getFusedLocationProviderClient(context)
    return GoogleApiAvailability.getInstance()
        .checkApiAvailability(client)
        .onSuccessTask { _ -> client.lastLocation }
        .addOnFailureListener { _ -> Log.d(TAG, "Location unavailable.")}
}

Java

public Task<Location> getLastLocationIfApiAvailable(Context context) {
    FusedLocationProviderClient client =
            getFusedLocationProviderClient(context);
    return GoogleApiAvailability.getInstance()
            .checkApiAvailability(client)
            .onSuccessTask(unused -> client.getLastLocation())
            .addOnFailureListener(e -> Log.d(TAG, "Location unavailable."));
}