Kacper Drapała

Integracja aplikacji na Android z Google Drive

W tym wpisie zajmę się omawianiem szczegółów dotyczących integracji aplikacji na Androida z Google Drive wykorzystując do tego Google Drive API. W naszej aplikacji będzie możliwość tworzenia, zapisywania oraz pobierania danych z naszego dysku Google. Całość projektu będzie możliwa do pobrania na GitHubie.

Wprowadzenie

Sam Google udostępnia dla użytkowników system dysku online. Udostępniane nam są takie opcje jak wgrywania czy pobierania plików do chmury, dzięki którym jesteśmy w stanie z każdego urządzenia połączyć się pod dany dysk wykorzystując do tego konto Googla i pobrać pliki.

Google Drive API umożliwia integrację pomiędzy naszymi aplikacjami, a usługami Google Drive.

Stworzenie projektu

W moim przypadku projekt tworzę w Android Studio 2.3.1. Nie stoi nic na przeszkodzie w korzystaniu innych IDE. Podczas tworzenia projektu należy wybrać na jakim systemie będzie pracować nasza aplikacja. Ja wybrałem Android 6.0. W kolejnym kroku zaznaczyłem by stworzyło mi projekt z pustą aktywnością.

Google Developer Console – czyli tworzenie nowej aplikacji

Tworzenie aplikacji, która będzie w stanie zapisywać oraz odczytywać pliki z Google Drive rozpoczynamy poprzez stworzenie nowego projektu w systemie Google Developer Console.

Aktywacja Google Drive API

W tym momencie projekt już istnieje więc możemy aktywować nasz dysk. Aktywacja Google Drive API dla naszej aplikacji odbywa się poprzez podaną wcześniej stronę. Przechodzimy do zakładki Biblioteka, następnie wybieramy Drive API oraz klikamy Włącz.

Następnie musimy wskazać w jaki sposób będziemy autoryzować nasz projekt z usługami Google. W uruchomionym wcześniej interfejsie pokażę nam się komunikat:

Jeśli chcesz używać tego interfejsu API, możesz potrzebować danych logowania. Kliknij „Utwórz dane logowania”, aby rozpocząć.

Obok napisu mamy guzik Utwórz dane logowania, klikamy go.

Krok 1: zaznaczamy to co na obrazku i idziemy dalej. Klikamy niebieski guzik.

Krok 2:

W tym miejscu musimy wpisać nazwę naszego klucza, odcisk palca certyfikatu SHA-1 oraz nazwę pakietu.

Zacznijmy od prostszej sprawy. Wpisujemy nazwę pakietu.

Należy pamiętać aby nazwa pakietu była taka sama jak w AndroidManifest.xml w miejscu package!

Kolejnym krokiem jest wygenerowanie naszego cyfrowego odcisku palca SHA-1. W tym celu należy uruchomić konsolę w systemie, oraz przejść do folderu z naszym keytool.exe. U mnie C:\Program Files\Java\jdk1.8.0_131\bin

Wklejamy,

keytool -exportcert -list -v -alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore

oraz wpisujemy hasło android

Zapisujemy zmiany.

Krok 3 i ostatni:

Został stworzony klucz Client ID, którym będziemy mogli wykorzystywać z naszej aplikacji do łączenia się z Google Drive API.

Dodanie zezwoleń

Na początku jednak musimy przygotować nasz projekt pod dalsze czynności. Musimy dać możliwość naszej aplikacji z korzystania internetu i innych usług.

Do naszego pliku AndroidManifest.xml dodajemy tę linijkę

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

Instalacja oraz aktywacja Google Play Services w aplikacji

Będziemy wykorzystywać w naszej aplikacji interfejsu Google Drive Android API. Zanim jednak zaczniemy korzystać z naszego interfejsu musimy go zainstalować w naszej aplikacji. Należy kliknąć Tools>Android>SDK Manager. W otwartym oknie uruchamiamy zakładkę SDK Tools rozwijamy Support Repository, zaznaczamy Google Repository oraz klikamy OK. (często już jest zainstalowany)

Następnie dodajemy Google Play Services do naszego projektu.

W tym celu musimy otworzyć plik build.gradle (Module: app) oraz w ciele dependencie  doklejamy:

compile 'com.google.android.gms:play-services-drive:10.2.4'

zapisujemy oraz synchronizujemy projekt z plikami .gradle

Kolejnym elementem jest dodanie do pliku AndroidManifest.xml linijek dotyczących naszego klucza Client ID.

<meta-data 
 android:name="com.google.android.apps.drive.APP_ID" 
 android:value="id=xxxxxxxxxxx.apps.googleusercontent.com" /> <!-- CLIENT ID -->

<meta-data
 android:name="com.google.android.gms.version"
 android:value="@integer/google_play_services_version" />

Tworzenie aplikacji – wygląd

<Button
 android:id="@+id/saveButton"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:onClick="onClickCreateFile"
 android:text="Zapisz przykładowy plik na dysku" />

<Button
 android:id="@+id/openButton"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:onClick="onClickOpenFile"
 android:text="Otwórz pliki z dysku" />

<Button
 android:id="@+id/logoutButton"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:onClick="onClickLogout"
 android:text="Wyloguj" />

MainActivity.java – zaczynamy

Nasza klasa musi zostać rozszerzona poprzez klasę Activity.

public class MainActivity extends Activity {
private static final String TAG = "Google Drive Activity";
}

Dodajemy pierwszą metodę onCreate(), która jest wywoływana w momencie uruchamiania aplikacji.

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

Nawiązywanie i kończenie połączenia z Google Drive API

W naszym MainAcitivity.java dodajemy zmienną globalną

private GoogleApiClient mGoogleApiClient;

oraz kolejno metody:

Nawiązywanie połączenia

@Override
protected void onResume() {
    super.onResume();
    if (mGoogleApiClient == null) {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }
    mGoogleApiClient.connect();
}

Kończenie połączenia. W momencie gdy nasza aktywność zostanie zatrzymana (np. przejdziemy do pulpitu), wywoła się metoda onStop(). Właśnie w tym momencie rozłączamy się z naszym Google Drive API. Dodatkowo implementujemy metodę onClickLogout(), która zostanie wywołana w momencie kliknięcia guzika Wyloguj. Ta metoda kasuje dotychczasowe połączenie z Googlem i nawiązuje połączenie kolejny raz, np. po to, aby wybrać inne konto Google.

@Override
protected void onStop() {
    super.onStop();
    if (mGoogleApiClient != null) {
        mGoogleApiClient.disconnect();
    }
    super.onPause();
}
public void onClickLogout(View view) {
    mGoogleApiClient.clearDefaultAccountAndReconnect().setResultCallback((new ResultCallback<Status>() {
        @Override
        public void onResult(@NonNull Status status) {
            Toast.makeText(getApplicationContext(), "Wylogowano", Toast.LENGTH_LONG).show();
        }
    }));
}

Implementacja interfejsów ConnectionCallbacks oraz OnConnectionFailedListener

Dodajemy do zmiennych globalnych

private static final int REQUEST_CODE_RESOLUTION = 1;

Zaimplementujemy teraz interfejsy ConnectionCallbacks oraz OnConnectionFailedListener by wiedzieć jaki aktualnie posiadamy status połączenia z Google API. Interfejsy te dodają nam 3 metody kolejno onConnected(), onConnectionSuspended() oraz onConnectionFailed(), które przechwytują wszelkie nieprawidłowości związane z połączeniem pomiędzy aplikacją, a usługą Google Drive API.

W momencie kiedy użytkownik został upoważniony przez Google API zostaje wywołana metoda onConnected()

@Override
public void onConnected(Bundle connectionHint) {
    Toast.makeText(getApplicationContext(), "Zalogowano ", Toast.LENGTH_LONG).show();
}

W momencie kiedy użytkownik został odrzucony przez Google API, zostaje wywołana metoda onConnectionFailed() oraz wyświetla się okno z informacją, że nasza aplikacja nie posiada dostępu do Google Drive.

@Override
public void onConnectionFailed(ConnectionResult result) {
    Log.i(TAG, "GoogleApiClient połączenie nieudane: " + result.toString());
    if (result.hasResolution()) {
        try {
            result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
        } catch (IntentSender.SendIntentException e) {
            e.printStackTrace();
        }
    } else {
        GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), 0).show();
    }
}

W przypadku zawieszenie połączenia, wywoływana jest metoda onConnectionSuspended()

@Override
public void onConnectionSuspended(int cause) {
    Log.i(TAG, "GoogleApiClient połączenie wstrzymane.");
}

Pierwsze uruchomienie aplikacji

Przy pierwszym uruchomieniu aplikacji poprosi nas o dodanie konta Googla do systemu.

Dodajemy konto.

Następnie aplikacja poprosi nas o połączenie aplikacji z naszym kontem oraz o zezwolenie do Google Drive

Po zezwoleniu zostaniemy zalogowani do aplikacji. Wyświetli się informacja Zalogowano.

Na naszym koncie możemy teraz zobaczyć naszą aplikację która została powiązana z kontem.

Tworzenie naszego pliku

W tym kroku stworzymy nasz pierwszy plik tekstowy. Użyjemy do tego metody createFile() na obiekcie Drive. Plik ten zostanie stworzony w głównym folderze dysku.

Tworzenie metody onClick()

Nasz guzik Zapisz przykładowy plik na dysku posiada w polu onClick podaną nazwę metody onClickCreateFile.

Dodajemy metodę

public void onClickCreateFile(View view) {
    Drive.DriveApi.newDriveContents(mGoogleApiClient).setResultCallback(driveContentsCallback);
}

Podczas kliknięcia na guzik zostaję wywołana ta własnie metoda, ustawia zmienną fileOperation i podaję nasze połączenie z API do DriveContents, kolejno uruchamia metodę callback driveContentsCallback.

Przechwytywanie wyników DriveContents

final ResultCallback<DriveApi.DriveContentsResult> driveContentsCallback =
        new ResultCallback<DriveApi.DriveContentsResult>() {
            @Override
            public void onResult(DriveApi.DriveContentsResult result) {
                if (result.getStatus().isSuccess()) {
                    CreateFileOnGoogleDrive(result);
                }
            }
        };

Jeśli wszystko przebiegło pomyślnie zostanie wywołana metoda CreateFileOnGoogleDrive().

Logika tworzenia pliku

public void CreateFileOnGoogleDrive(DriveApi.DriveContentsResult result) {
    final DriveContents driveContents = result.getDriveContents();
    OutputStream outputStream = driveContents.getOutputStream();
    Writer writer = new OutputStreamWriter(outputStream);
    try {
        writer.write("Witaj świecie! To nasz pierwszy plik zapisany z aplikacji na Androida");
        writer.close();
    } catch (IOException e) {
        Log.e(TAG, e.getMessage());
    }
    MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
            .setTitle("AndroidTestFile")
            .setMimeType("text/plain")
            .setStarred(true).build();

    Drive.DriveApi.getRootFolder(mGoogleApiClient)
            .createFile(mGoogleApiClient, changeSet, driveContents)
            .setResultCallback(fileCallback);
}

Cała logika to nic innego jak wrzucenie do driveContents naszego strumienia danych. Operacje wykonujemy tak jak dla zwykłego pliku tekstowego, który chcemy zapisać na naszym lokalnym dysku. Po stworzeniu takiego dysku ustawia dla pliku nazwę oraz typ pliku.

Następnie pobiera dla naszego połączenia Google Drive API ścieżkę folderu głównego i w nim tworzy nasz wcześniej utworzony plik. Na końcu wywołana jest metoda callback fileCallback, która w momencie prawidłowego utworzenia pliku na dysku wyświetli napis iż plik został stworzony.

Przechwytywanie wyników stworzonego pliku

Naszą metodą do przechwytywania wyników dla stworzonego pliku była fileCallback. Oto ona

final private ResultCallback<DriveFolder.DriveFileResult> fileCallback = new
        ResultCallback<DriveFolder.DriveFileResult>() {
            @Override
            public void onResult(DriveFolder.DriveFileResult result) {
                if (result.getStatus().isSuccess()) {
                    Toast.makeText(getApplicationContext(), "Plik stworzony: " + "" + result.getDriveFile().getDriveId(), Toast.LENGTH_LONG).show();
                }
            }
        };

Czytanie plików z dysku

public void onClickOpenFile(View view) {
    IntentSender intentSender = Drive.DriveApi
            .newOpenFileActivityBuilder()
            .setMimeType(new String[]{"text/plain", "text/html", "image/jpeg","image/png"})
            .build(mGoogleApiClient);
    try {
        startIntentSenderForResult(intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0);
    } catch (IntentSender.SendIntentException e) {
        Log.w(TAG, "Nie można wysłać żądania", e);
    }
}

Zdarzenie onClickOpenFile() wykona się w momencie naciśnięcia guzika Otwórz pliki z dysku.

Aby ustawić możliwość czytania konkretnych plików z danym rozszerzeniem, dodajemy kolejne elementy w tablicy dla parametru metody setMimeType().

Wszystkie typy możecie znaleźć pod tym adresem.

Uruchomienie pliku poprzez kliknięcie

Dodajemy do zmiennych globalnych

private static final int REQUEST_CODE_OPENER = 2;

Aktywność onActivityResult zostanie wywołana w momencie, gdy użytkownik zaznaczy plik na dysku danego rozszerzenia, który wcześniej ustawiliśmy w setMimeTypes(). W tej metodzie pobieramy id zaznaczonego pliku oraz otwieramy go w przeglądarce.

@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
    switch (requestCode) {
        case REQUEST_CODE_OPENER:
            if (resultCode == RESULT_OK) {
                mFileId = (DriveId) data.getParcelableExtra(
                        OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID);

                Log.e("file id", mFileId.getResourceId() + "");

                String url = "https://drive.google.com/open?id=" + mFileId.getResourceId();

                Intent i = new Intent(Intent.ACTION_VIEW);
                i.setData(Uri.parse(url));
                startActivity(i);
            }
            break;
        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    }
}

Koniec

W tym wpisie pokazałem w jaki sposób zintegrować naszą aplikację na Androida z Google Drive. Storzyliśmy przykładowy plik w folderze głównym oraz dodaliśmy możliwość listowania wszystkich plików na dysku. Cały przykład znajdziecie na moim GitHubie.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *