Chamar APIs de back-end a partir de um cliente Android

Esta página descreve como um cliente Android chama uma API de back-end criada com os Frameworks Cloud Endpoints para o App Engine.

Gerar a biblioteca de cliente

O seu cliente Android requer a biblioteca cliente gerada a partir da API de back-end que o cliente está a usar. Se ainda não tiver a biblioteca de cliente, consulte o artigo Gerar uma biblioteca de cliente para ver detalhes. Existem passos neste documento que explicam como adicionar a biblioteca de cliente ao projeto de cliente Android.

Configurar o projeto

Nestas instruções, usa o Android Studio. Se ainda não o fez, tem de configurar o Android Studio para suportar um cliente que use as frameworks.

Configurar o projeto

No Android Studio, o seu projeto usa o ficheiro build.gradle para dependências e outras definições. Por predefinição, o Android Studio cria um ficheiro build.gradle ao nível do projeto principal e um específico da app Android no módulo Android. Estas instruções destinam-se ao build.gradle específico da app no módulo Android.

Para configurar o build.gradle:

  1. Clique duas vezes em build.gradle para o abrir.

  2. Edite este ficheiro para que contenha as seguintes linhas:

    buildscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:1.0.0'
        }
    }
    apply plugin: 'com.android.application'
    
    repositories {
        mavenCentral()
        mavenLocal()
    }
    
    android {
        compileSdkVersion 26
    
        defaultConfig {
            applicationId "com.mycompany.myapp"
            minSdkVersion 17
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        packagingOptions {
            exclude 'META-INF/DEPENDENCIES'
        }
    }
    
    dependencies {
        implementation 'com.android.support:appcompat-v7:26.1.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        // BEGIN Google APIs
        // Play Services will validate the application prior to allowing OAuth2 access.
        implementation 'com.google.android.gms:play-services-auth:16.0.0'
        implementation 'com.google.android.gms:play-services-identity:16.0.0'
        // The following lines implement maven imports as defined at:
        // https://github.com/googleapis/google-api-java-client/wiki/Setup-Instructions
        // Add the Google API client library.
        implementation('com.google.api-client:google-api-client:1.28.0') {
            // Exclude artifacts that the Android SDK/Runtime provides.
            exclude(group: 'xpp3', module: 'xpp3')
            exclude(group: 'org.apache.httpcomponents', module: 'httpclient')
            exclude(group: 'junit', module: 'junit')
            exclude(group: 'com.google.android', module: 'android')
        }
        // Add the Android extensions for the Google API client library.
        // This will automatically include play services as long as you have download that library
        // from the Android SDK manager.
        // Add the Android extensions for the Google API client library.
        implementation(group: 'com.google.api-client', name: 'google-api-client-android', version: '1.25.0') {
                   // Exclude play services, since we're not using this yet.
                  exclude(group: 'com.google.android.gms:play-services', module: 'google-play-services')
        }
        // END Google APIs
        // The following client libraries make HTTP/JSON on Android easier.
        // Android extensions for Google HTTP Client.
        implementation('com.google.http-client:google-http-client-android:1.21.0') {
            exclude(group: 'com.google.android', module: 'android')
        }
        implementation 'com.google.http-client:google-http-client-gson:1.21.0'
        // This is used by the Google HTTP client library.
        implementation 'com.google.guava:guava:18.0+'
        implementation files('libs/echo-v1-1.25.0-SNAPSHOT.jar')
    }
    
    

    Substitua com.mycompany.myapp pelos seus próprios valores.

  3. Clique em Ficheiro > Guardar tudo e, de seguida, saia do Android Studio e reinicie-o.

Adicionar a biblioteca de cliente ao projeto

Para adicionar a biblioteca de cliente ao projeto Android:

  1. Adicione um diretório /libs ao seu projeto, se ainda não tiver um. É um par do diretório /src.

  2. Copie a biblioteca cliente gerada a partir da API de back-end para /libs.

  3. Clique com o botão direito do rato na biblioteca que acabou de adicionar e, de seguida, selecione Adicionar como biblioteca ao seu projeto.

Criar o objeto de serviço

No código do projeto, tem de usar um objeto de serviço para fazer pedidos à API de back-end. Para pedidos não autenticados, crie o objeto de serviço da seguinte forma:

BACKEND_API_NAME.Builder builder = new BACKEND_API_NAME.Builder(
    NetHttpTransport(), new GsonFactory(), null);
service = builder.build();

Substitua BACKEND_API_NAME pelo nome da API de back-end.

Chamar a API de back-end

No seu projeto, chame a API através do objeto de serviço. Por exemplo:

ScoreCollection scores = service.scores().list().execute();

Neste fragmento, está a pedir uma lista de todos os objetos Score no servidor. Se listparâmetros obrigatórios, ou um corpo do pedido, fornecê-los no comando. O Android Studio oferece a conclusão de código para identificar as chamadas de métodos disponíveis e os respetivos parâmetros necessários.

É importante ter em atenção que, uma vez que as chamadas da API resultam em pedidos através da rede, tem de fazer pedidos no respetivo segmento. (Este requisito foi adicionado às versões recentes do Android, mas é uma prática recomendada mesmo em versões mais antigas.) Para o fazer, usa um Thread ou um AsyncTask. Por exemplo:

private class QueryScoresTask extends AsyncTask<Void, Void, ScoreCollection>{
  Context context;

  public QueryScoresTask(Context context) {
    this.context = context;
  }

  protected Scores doInBackground(Void... unused) {
    ScoreCollection scores = null;
    try {
      scores = service.scores().list().execute();
    } catch (IOException e) {
      Log.d("TicTacToe", e.getMessage(), e);
    }
    return scores;
  }

  protected void onPostExecute(ScoreCollection scores) {
    // Do something with the result.
  }
}

Fazer chamadas autenticadas

Estas instruções abrangem apenas a programação do cliente que tem de adicionar. Partem do princípio que já adicionou o suporte dos Frameworks de Endpoints para autenticação, conforme descrito em Autenticar utilizadores.

Se o seu cliente Android estiver a fazer chamadas para um ponto final que requer autenticação, tem de:

  • Configure o cliente Android para fornecer credenciais ao objeto de serviço.
  • Use o selecionador de contas para suportar a escolha do utilizador das contas de início de sessão.

As secções seguintes fornecem detalhes.

Configurar o cliente Android para fornecer credenciais

Para suportar pedidos a uma API de back-end que requer autenticação, o seu cliente Android tem de obter credenciais do utilizador e transmiti-las ao objeto de serviço.

A obtenção das credenciais do utilizador e a utilização do seletor de contas requerem que tenha as seguintes autorizações do Android:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />

Para obter as credenciais do utilizador, chame GoogleAccountCredential.usingAudience da seguinte forma:

// Inside your Activity class onCreate method
settings = getSharedPreferences(
    "TicTacToeSample", 0);
credential = GoogleAccountCredential.usingAudience(this,
    "server:client_id:1-web-app.apps.googleusercontent.com");

Em que o segundo parâmetro da chamada é o prefixo server:client_id adicionado ao ID de cliente Web da API de back-end.

Exemplo de código: obter credenciais para o objeto de serviço

O código seguinte mostra como obter credenciais e transmiti-las ao objeto de serviço:

// Inside your Activity class onCreate method
settings = getSharedPreferences("TicTacToeSample", 0);
credential = GoogleAccountCredential.usingAudience(this,
    "server:client_id:1-web-app.apps.googleusercontent.com");
setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));

Tictactoe.Builder builder = new Tictactoe.Builder(
    NetHttpTransport(), new GsonFactory(),
    credential);
service = builder.build();

if (credential.getSelectedAccountName() != null) {
  // Already signed in, begin app!
} else {
  // Not signed in, show login window or request an account.
}

// setSelectedAccountName definition
private void setSelectedAccountName(String accountName) {
  SharedPreferences.Editor editor = settings.edit();
  editor.putString(PREF_ACCOUNT_NAME, accountName);
  editor.commit();
  credential.setSelectedAccountName(accountName);
  this.accountName = accountName;
}

O exemplo de código anterior procura quaisquer preferências partilhadas armazenadas pela app Android e tenta encontrar o nome da conta que o utilizador quer usar para se autenticar na sua aplicação. Se for bem-sucedido, o código cria um objeto credentials e transfere-o para o objeto de serviço. Estas credenciais permitem que a sua app Android transmita o token adequado ao seu back-end.

Tenha em atenção que o exemplo de código verifica se a app Android já sabe que conta usar. Se o fizer, o fluxo lógico pode continuar e executar a app Android. Se a app não souber que conta usar, apresenta um ecrã de início de sessão ou pede ao utilizador para escolher uma conta.

Por fim, o exemplo cria um objeto de credenciais e passa-o para o objeto de serviço. Estas credenciais permitem que a sua app Android transmita o token adequado à sua app Web do App Engine.

Usar o selecionador de contas

O Android fornece uma intenção para selecionar uma conta de utilizador. Pode invocar esta função da seguinte forma:

static final int REQUEST_ACCOUNT_PICKER = 2;

void chooseAccount() {
  startActivityForResult(credential.newChooseAccountIntent(),
      REQUEST_ACCOUNT_PICKER);
}

Aqui é apresentado um controlador para interpretar o resultado deste objetivo:

@Override
protected void onActivityResult(int requestCode, int resultCode,
   Intent data) {
 super.onActivityResult(requestCode, resultCode, data);
 switch (requestCode) {
   case REQUEST_ACCOUNT_PICKER:
     if (data != null && data.getExtras() != null) {
       String accountName =
           data.getExtras().getString(
               AccountManager.KEY_ACCOUNT_NAME);
       if (accountName != null) {
         setSelectedAccountName(accountName);
         SharedPreferences.Editor editor = settings.edit();
         editor.putString(PREF_ACCOUNT_NAME, accountName);
         editor.commit();
         // User is authorized.
       }
     }
     break;
  }
}

Testar um cliente Android num servidor de desenvolvimento local

Pode testar o seu cliente em relação a uma API de back-end em execução no App Engine de produção em qualquer altura sem fazer alterações. No entanto, se quiser testar o seu cliente em relação a uma API de back-end executada no servidor de desenvolvimento local, tem de alterar a linha de código no cliente para apontar para o endereço IP da máquina que executa o servidor de desenvolvimento local.

Para fazer as alterações necessárias e testar através do servidor de desenvolvimento local:

  1. Tome nota do endereço IP da máquina que está a executar o servidor de desenvolvimento local, uma vez que precisa dele quando adicionar código ao cliente Android.

  2. Inicie o servidor de desenvolvimento local, conforme descrito em Testar uma API localmente.

  3. No projeto do cliente do Android Studio, localize o código que obtém o identificador do serviço da API de back-end. Normalmente, este código usa um Builder para configurar o pedido da API.

  4. Substitua o URL raiz no objeto Builder (este é o URL ao qual o cliente Android se liga na chamada API de back-end) adicionando a linha:

    yourBuilderObject.setRootUrl("http://YOUR_MACHINE_IP_ADDRESS:8080/_ah/api");
    

    Por exemplo:

    public static Helloworld getApiServiceHandle(@Nullable GoogleAccountCredential credential) {
      // Use a builder to help formulate the API request.
      Helloworld.Builder helloWorld = new Helloworld.Builder(AppConstants.HTTP_TRANSPORT,
          AppConstants.JSON_FACTORY,credential);
    
      helloWorld.setRootUrl("http://YOUR_MACHINE_IP_ADDRESS:8080/_ah/api");
      return helloWorld.build();
    }
    

    Substitua YOUR_MACHINE_IP_ADDRESS pelo endereço IP do seu sistema.

  5. Recompile o projeto do cliente Android.

  6. Se quiser executar a sua app de cliente num emulador do AVD:

    1. No Android Studio, aceda a Tools > Android > AVD Manager e inicie um AVD existente, se tiver um. Caso contrário, crie um e, em seguida, inicie-o.
    2. Aceda a Executar > Depurar YOUR_PROJECT_NAME onde YOUR_PROJECT_NAME representa o nome do seu Google Cloud projeto.
    3. Quando lhe for pedido que escolha um dispositivo, selecione o seu AVD.
    4. Teste o seu cliente.
  7. Se quiser executar a app cliente num dispositivo Android físico:

    1. Certifique-se de que o dispositivo Android está ativado para depuração.
    2. No Android Studio, aceda a Executar > Depurar YOUR_PROJECT_NAME.
    3. Quando lhe for pedido para escolher um dispositivo, selecione o seu dispositivo Android físico.
    4. Teste o seu cliente.

Exemplo de código fonte do cliente

Para ver um exemplo de código, consulte o exemplo do Android Cloud Endpoints v2.0.