2012-10-28 97 views
6

我正在嘗試實施Stephen Wylie的Google Drive示例(here)。這裏是我的代碼:未找到Google Drive SDK活動例外

package com.googledrive.googledriveapp; 
// For Google Drive/Play Services 
// Version 1.1 - Added new comments & removed dead code 
// Stephen Wylie - 10/20/2012 
import java.io.IOException; 
import java.util.ArrayList; 

import android.accounts.Account; 
import android.accounts.AccountManager; 
import android.app.Activity; 
import android.app.ProgressDialog; 
import android.content.Context; 
import android.content.DialogInterface; 
import android.content.DialogInterface.OnClickListener; 
import android.content.Intent; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.View; 
import android.widget.Button; 

import com.google.android.gms.auth.GoogleAuthException; 
import com.google.android.gms.auth.GoogleAuthUtil; 
import com.google.android.gms.auth.UserRecoverableAuthException; 
import com.google.android.gms.common.AccountPicker; 
import com.google.api.client.auth.oauth2.BearerToken; 
import com.google.api.client.auth.oauth2.Credential; 
import com.google.api.client.extensions.android2.AndroidHttp; 
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager; 
import com.google.api.client.http.HttpRequestFactory; 
import com.google.api.client.http.HttpTransport; 
import com.google.api.client.http.json.JsonHttpRequest; 
import com.google.api.client.http.json.JsonHttpRequestInitializer; 
import com.google.api.client.json.jackson.JacksonFactory; 
import com.google.api.services.drive.Drive; 
import com.google.api.services.drive.Drive.Apps.List; 
import com.google.api.services.drive.Drive.Files; 
import com.google.api.services.drive.DriveRequest; 
import com.google.api.services.drive.DriveScopes; 
import com.google.api.services.drive.model.File; 
import com.google.api.services.drive.model.FileList; 

public class MainActivity extends Activity { 
    private static final int CHOOSE_ACCOUNT=0; 
    private static String accountName; 
    private static int REQUEST_TOKEN=0; 
    private Button btn_drive; 
    private Context ctx = this; 
    private Activity a = this; 

    public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     // set up the GUI layout 
     setContentView(R.layout.activity_main); 
     // set the variables to access the GUI controls 
     btn_drive = (Button) findViewById(R.id.btn_drive); 
      btn_drive.setOnClickListener(new View.OnClickListener() { 
      public void onClick(View v) { 
       chooseAccount(); 
      } 
      }); 
    } 

    public void chooseAccount() { 
     Intent intent = AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null, null, null, null); 
     startActivityForResult(intent, CHOOSE_ACCOUNT); 
    } 

    // Fetch the access token asynchronously. 
    void getAndUseAuthTokenInAsyncTask(Account account) { 
     AsyncTask<Account, String, String> task = new AsyncTask<Account, String, String>() { 
      ProgressDialog progressDlg; 
      AsyncTask<Account, String, String> me = this; 

      @Override 
      protected void onPreExecute() { 
       progressDlg = new ProgressDialog(ctx, ProgressDialog.STYLE_SPINNER); 
       progressDlg.setMax(100); 
       progressDlg.setTitle("Validating..."); 
       progressDlg.setMessage("Verifying the login data you entered...\n\nThis action will time out after 10 seconds."); 
       progressDlg.setCancelable(false); 
       progressDlg.setIndeterminate(false); 
       progressDlg.setOnCancelListener(new android.content.DialogInterface.OnCancelListener() { 
        public void onCancel(DialogInterface d) { 
         progressDlg.dismiss(); 
         me.cancel(true); 
        } 
       }); 
       progressDlg.show(); 
      } 

      @Override 
      protected String doInBackground(Account... params) { 
       return getAccessToken(params[0]); 
      } 

      @Override 
      protected void onPostExecute(String s) { 
       if (s == null) { 
        // Wait for the extra intent 
       } else { 
        accountName = s; 
        getDriveFiles(); 
       } 
       progressDlg.dismiss(); 
      } 
     }; 
     task.execute(account); 
    } 

    /** 
    * Fetches the token from a particular Google account chosen by the user. DO NOT RUN THIS DIRECTLY. It must be run asynchronously inside an AsyncTask. 
    * @param activity 
    * @param account 
    * @return 
    */ 
    private String getAccessToken(Account account) { 
     try { 
      return GoogleAuthUtil.getToken(ctx, account.name, "oauth2:" + DriveScopes.DRIVE_READONLY); // IMPORTANT: DriveScopes must be changed depending on what level of access you want 
     } catch (UserRecoverableAuthException e) { 
      // Start the Approval Screen intent, if not run from an Activity, add the Intent.FLAG_ACTIVITY_NEW_TASK flag. 
      a.startActivityForResult(e.getIntent(), REQUEST_TOKEN); 
      e.printStackTrace(); 
      return null; 
     } catch (GoogleAuthException e) { 
      e.printStackTrace(); 
      return null; 
     } catch (IOException e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    private Drive getDriveService() { 
     HttpTransport ht = AndroidHttp.newCompatibleTransport();    // Makes a transport compatible with both Android 2.2- and 2.3+ 
     JacksonFactory jf = new JacksonFactory();       // You need a JSON parser to help you out with the API response 
     Credential credential = new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(accountName); 
     HttpRequestFactory rf = ht.createRequestFactory(credential); 
     Drive.Builder b = new Drive.Builder(ht, jf, null); 
     b.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() { 

      @Override 
      public void initialize(JsonHttpRequest request) throws IOException { 
       DriveRequest driveRequest = (DriveRequest) request; 
       driveRequest.setPrettyPrint(true); 
       driveRequest.setOauthToken(accountName); 
      } 
     }); 
     return b.build(); 
    } 

    /** 
    * Obtains a list of all files on the signed-in user's Google Drive account. 
    */ 
    private void getDriveFiles() { 
     Drive service = getDriveService(); 
     Log.d("SiteTrack", "FUNCTION getDriveFiles()"); 
     Files.List request; 
     try { 
      request = service.files().list(); // .setQ("mimeType=\"text/plain\""); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      return; 
     } 
     do { 
      FileList files; 
      try { 
       Log.d("SiteTrack", request.toString()); 
       files = request.execute(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
       Log.d("SiteTrack", "Exception"); 
       return; 
      } 
      ArrayList<File> fileList = (ArrayList<File>) files.getItems(); 
      Log.d("SiteTrack", "Files found: " + files.getItems().size()); 
      for (File f : fileList) { 
       String fileId = f.getId(); 
       String title = f.getTitle(); 
       Log.d("SiteTrack", "File " + fileId + ": " + title); 
      } 
      request.setPageToken(files.getNextPageToken()); 
     } while (request.getPageToken() != null && request.getPageToken().length() >= 0); 
    } 

    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { 
     if (requestCode == CHOOSE_ACCOUNT && resultCode == RESULT_OK) { 
      accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); 
      GoogleAccountManager gam = new GoogleAccountManager(this); 
      getAndUseAuthTokenInAsyncTask(gam.getAccountByName(accountName)); 
      Log.d("SiteTrack", "CHOOSE_ACCOUNT"); 
     } else if (requestCode == REQUEST_TOKEN && resultCode == RESULT_OK) { 
      accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); 
      Log.d("SiteTrack", "REQUEST_TOKEN"); 
     } 
    } 
} 

這裏是我的清單:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.googledrive.googledriveapp" 
    android:versionCode="1" 
    android:versionName="1.0" > 

    <uses-sdk 
     android:minSdkVersion="8" 
     android:targetSdkVersion="15" /> 

    <application 
     android:icon="@drawable/ic_launcher" 
     android:label="@string/app_name" 
     android:theme="@style/AppTheme" > 
     <activity 
      android:name=".MainActivity" 
      android:label="@string/title_activity_main" > 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 

       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
      <meta-data 
       android:name="android.support.PARENT_ACTIVITY" 
       android:value="android.app.ActivityGroup" /> 
     </activity> 
    </application> 
    <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 
    <uses-permission android:name="android.permission.INTERNET" /> 
</manifest> 

這裏是我的activity_main.xml中:

<?xml version="1.0" encoding="utf-8"?> 

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <Button 
     android:id="@+id/btn_drive" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Connect to Google Drive" /> 
</LinearLayout> 

這裏是logcat的錯誤我收到。它發生在按下按鈕時:

10-28 00:25:28.637: E/AndroidRuntime(842): android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.google.android.gms.common.account.CHOOSE_ACCOUNT (has extras) } 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1512) 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1384) 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.app.Activity.startActivityForResult(Activity.java:3190) 
10-28 00:25:28.637: E/AndroidRuntime(842): at com.googledrive.googledriveapp.MainActivity.chooseAccount(MainActivity.java:67) 
10-28 00:25:28.637: E/AndroidRuntime(842): at com.googledrive.googledriveapp.MainActivity$1.onClick(MainActivity.java:60) 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.view.View.performClick(View.java:3511) 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.view.View$PerformClick.run(View.java:14105) 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.os.Handler.handleCallback(Handler.java:605) 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.os.Handler.dispatchMessage(Handler.java:92) 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.os.Looper.loop(Looper.java:137) 
10-28 00:25:28.637: E/AndroidRuntime(842): at android.app.ActivityThread.main(ActivityThread.java:4424) 
10-28 00:25:28.637: E/AndroidRuntime(842): at java.lang.reflect.Method.invokeNative(Native Method) 
10-28 00:25:28.637: E/AndroidRuntime(842): at java.lang.reflect.Method.invoke(Method.java:511) 
10-28 00:25:28.637: E/AndroidRuntime(842): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
10-28 00:25:28.637: E/AndroidRuntime(842): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
10-28 00:25:28.637: E/AndroidRuntime(842): at dalvik.system.NativeStart.main(Native Method) 

任何人都可以幫忙嗎?

回答

7

谷歌Drive API似乎(根據谷歌的人)只能在真實的設備上工作,在模擬器中它會崩潰並出現此錯誤。

所以我的建議,嘗試一個真正的設備。

+0

是的,我聽到過同樣的事情 - 有點不幸。好吧。感謝您打開一個冷櫃。 –

+0

正在與Google人員交談,得到了同樣的錯誤..他們告訴我...... – Frank

+0

這用於工作,現在它在API 23模擬器中也被破壞了。 – powder366

8

我們一直在做一些嘗試,而且我們目前的理論是,新的Google OAuth庫取決於具有最新版本的Google Play。

我們發現如果您的設備仍具有Android Marketplace或舊版Google Play,我們無法使OAuth正常工作。

因此,您可以嘗試打開Android Marketplace或Google Play應用以啓動升級。

打開Android Marketplace,接受升級至Google Play。
關閉市場,然後打開Goog​​le Play應用。 接受Google Play的服務條款。 等幾秒鐘,犧牲一隻雞,然後你應該可以運行Google OAuth。

編輯:看起來像谷歌提供一些指導,你的應用程序應該做什麼,如果你的用戶缺少正確的谷歌播放版本。見:https://developer.android.com/google/play-services/setup.html#ensure