קריאה לממשקי API של קצה עורפי מלקוח Android

בדף הזה מוסבר איך לקוח Android קורא ל-API בקצה העורפי שנבנה באמצעות Cloud Endpoints Frameworks for App Engine.

יצירה של ספריית הלקוח

לקוח Android שלכם צריך את ספריית הלקוח שנוצרה מ-Backend API שבו הלקוח משתמש. אם עדיין אין לכם ספריית לקוח, תוכלו לקרוא את המאמר יצירה של ספריית לקוח. במאמר הזה מוסבר איך מוסיפים את ספריית הלקוח לפרויקט הלקוח של Android.

הגדרת הפרויקט

בהוראות האלה נעשה שימוש ב-Android Studio. אם עדיין לא עשיתם זאת, אתם צריכים להגדיר את Android Studio כך שיותאם ללקוח שמשתמש במסגרות.

הגדרת הפרויקט

ב-Android Studio, הפרויקט משתמש בקובץ build.gradle לתלות ולהגדרות אחרות. כברירת מחדל, Android Studio יוצר קובץ build.gradle ברמת פרויקט האב וקובץ ספציפי לאפליקציית Android במודול Android. ההוראות האלה מתייחסות ל-build.gradle הספציפי לאפליקציה במודול Android.

כדי להגדיר את build.gradle:

  1. לוחצים לחיצה כפולה על build.gradle כדי לפתוח אותו.

  2. עורכים את הקובץ כך שיכיל את השורות הבאות:

    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')
    }
    
    

    מחליפים את com.mycompany.myapp בערכים שלכם.

  3. לוחצים על File > Save All (קובץ > שמירת הכול), יוצאים מ-Android Studio ומפעילים אותו מחדש.

הוספת ספריית הלקוח לפרויקט

כדי להוסיף את ספריית הלקוח לפרויקט Android:

  1. מוסיפים ספרייה בשם /libs לפרויקט, אם עדיין אין בו ספרייה כזו. היא מקבילה לספרייה /src.

  2. מעתיקים את ספריית הלקוח שנוצרה מ-API הקצה העורפי אל /libs.

  3. לוחצים לחיצה ימנית על הספרייה שהוספתם ובוחרים באפשרות Add As Library (הוספה כספרייה) כדי להוסיף אותה לפרויקט.

יצירת אובייקט השירות

בקוד הפרויקט, צריך להשתמש באובייקט שירות כדי לשלוח בקשות ל-API של ה-Backend. עבור בקשות לא מאומתות, יוצרים את אובייקט השירות באופן הבא:

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

מחליפים את BACKEND_API_NAME בשם של ה-API של ה-Backend.

שליחת קריאה ל-API של ה-Backend

בפרויקט, קוראים ל-API באמצעות אובייקט השירות. לדוגמה:

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

בקטע הקוד הזה, אתם מבקשים רשימה של כל האובייקטים Score בשרת. אם list נדרשים פרמטרים או גוף בקשה, צריך לספק אותם בפקודה. ב-Android Studio יש השלמת קוד כדי לזהות קריאות זמינות לשיטות ואת הפרמטרים הנדרשים שלהן.

חשוב לזכור שקריאות ל-API יוצרות בקשות ברשת, ולכן צריך לבצע את הבקשות בשרשור משלהן. (הדרישה הזו נוספה לגרסאות האחרונות של Android, אבל מומלץ לפעול לפיה גם בגרסאות ישנות יותר). כדי לעשות את זה, משתמשים בפונקציה Thread או AsyncTask. לדוגמה:

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.
  }
}

ביצוע שיחות מאומתות

ההוראות האלה מתייחסות רק לקוד הלקוח שצריך להוסיף. אנחנו מניחים שכבר הוספתם את התמיכה ב-Endpoints Frameworks לאימות, כפי שמתואר במאמר בנושא אימות משתמשים.

אם לקוח Android שלכם מבצע קריאות לנקודת קצה שנדרש בה אימות, אתם צריכים:

  • מגדירים את לקוח Android כך שיספק פרטי כניסה לאובייקט השירות.
  • אפשר להשתמש בבוחר החשבונות כדי לתמוך באפשרויות בחירה למשתמשים של חשבונות להתחברות.

בקטעים הבאים מפורטים השלבים.

הגדרת לקוח Android כך שיספק פרטי כניסה

כדי לתמוך בבקשות ל-API של בק-אנד שדורש אימות, לקוח Android צריך לקבל פרטי כניסה של משתמש ולהעביר אותם לאובייקט השירות.

כדי לקבל את פרטי הכניסה של המשתמש ולהשתמש בבורר החשבונות, אתם צריכים את הרשאות Android הבאות:

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

כדי לקבל את פרטי הכניסה של המשתמש, קוראים ל-GoogleAccountCredential.usingAudience באופן הבא:

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

הפרמטר השני בקריאה הוא הקידומת server:client_id שנוספת לפני מזהה לקוח האינטרנט של ה-API של הבק-אנד.

קוד לדוגמה: קבלת פרטי כניסה לאובייקט השירות

הקוד הבא מראה איך מקבלים פרטי כניסה ומעבירים אותם לאובייקט השירות:

// 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;
}

קוד הדוגמה שלמעלה מחפש העדפות משותפות שמאוחסנות באפליקציית Android ומנסה למצוא את שם החשבון שהמשתמש רוצה להשתמש בו כדי לבצע אימות לאפליקציה. אם הפעולה בוצעה ללא שגיאות, הקוד יוצר אובייקט של פרטי כניסה ומעביר אותו לאובייקט השירות. פרטי הכניסה האלה מאפשרים לאפליקציית Android להעביר את האסימון המתאים לשרת העורפי.

שימו לב שבדוגמת הקוד יש בדיקה אם אפליקציית Android כבר יודעת באיזה חשבון להשתמש. אם כן, התהליך הלוגי יכול להימשך ולהפעיל את אפליקציית Android. אם האפליקציה לא יודעת באיזה חשבון להשתמש, היא מציגה מסך כניסה או מבקשת מהמשתמש לבחור חשבון.

לבסוף, הדוגמה יוצרת אובייקט של פרטי כניסה ומעבירה אותו לאובייקט השירות. פרטי הכניסה האלה מאפשרים לאפליקציית Android להעביר את האסימון המתאים לאפליקציית האינטרנט של App Engine.

שימוש בכלי לבחירת חשבונות

מערכת Android מספקת intent לבחירת חשבון משתמש. אפשר להפעיל את הפקודה הזו באופן הבא:

static final int REQUEST_ACCOUNT_PICKER = 2;

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

כאן מוצג handler לפרשנות של תוצאת הכוונה הזו:

@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;
  }
}

בדיקת לקוח Android מול שרת פיתוח מקומי

אתם יכולים לבדוק את הלקוח מול API של קצה עורפי שפועל ב-App Engine בסביבת הייצור בכל שלב, בלי לבצע שינויים. עם זאת, אם רוצים לבדוק את הלקוח מול API של בק-אנד שפועל בשרת הפיתוח המקומי, צריך לשנות את שורת הקוד בלקוח כך שתצביע על כתובת ה-IP של המחשב שבו פועל שרת הפיתוח המקומי.

כדי לבצע את השינויים הנדרשים ולבדוק באמצעות שרת הפיתוח המקומי:

  1. חשוב לרשום את כתובת ה-IP של המכונה שבה פועל שרת הפיתוח המקומי, כי תצטרכו אותה כשתוסיפו קוד ללקוח Android.

  2. מפעילים את שרת הפיתוח המקומי, כמו שמתואר במאמר הרצה ובדיקה של קצה עורפי של API באופן מקומי.

  3. בפרויקט הלקוח של Android Studio, מאתרים את הקוד שמקבל את ה-handle לשירות ה-API של ה-backend. בדרך כלל, הקוד הזה משתמש ב-Builder כדי להגדיר את בקשת ה-API.

  4. כדי לשנות את כתובת ה-URL הבסיסית באובייקט Builder (זו כתובת ה-URL שהלקוח של Android מתחבר אליה בקריאה ל-API בקצה העורפי), מוסיפים את השורה:

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

    לדוגמה:

    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();
    }
    

    מחליפים את YOUR_MACHINE_IP_ADDRESS בכתובת ה-IP של המערכת.

  5. בונים מחדש את פרויקט לקוח Android.

  6. אם רוצים להריץ את אפליקציית הלקוח באמולטור AVD:

    1. ב-Android Studio, עוברים אל Tools (כלים) > Android > AVD Manager (מנהל מכשירי ה-AVD) ומתחילים מכשיר AVD קיים אם יש כזה, או יוצרים מכשיר חדש ומתחילים אותו.
    2. עוברים אל Run ‏ > Debug YOUR_PROJECT_NAME, כאשר YOUR_PROJECT_NAME מייצג את השם של פרויקט Google Cloud .
    3. כשמופיעה בקשה לבחור מכשיר, בוחרים את ה-AVD.
    4. בודקים את הלקוח.
  7. אם רוצים להריץ את אפליקציית הלקוח במכשיר Android פיזי:

    1. מוודאים שהאפשרות 'ניפוי באגים' מופעלת במכשיר Android.
    2. ב-Android Studio, עוברים אל Run (הפעלה) > Debug YOUR_PROJECT_NAME (ניפוי באגים).
    3. כשמוצגת הנחיה לבחור מכשיר, בוחרים במכשיר ה-Android הפיזי.
    4. בודקים את הלקוח.

דוגמה של קוד מקור של לקוח

דוגמאות קוד אפשר למצוא בדוגמה ל-Android Cloud Endpoints v2.0.