如何使Android应用兼容Google Play开发者API的Java示例?
解决Android集成Google Play开发者API时的java.awt依赖问题
你遇到的核心问题是:Google提供的Java示例是针对桌面Java应用编写的,其中AuthorizationCodeInstalledApp依赖java.awt.Desktop(Android系统完全没有这个桌面类库),而LocalServerReceiver依赖Jetty服务器,同样不兼容Android环境。
下面给你两种可行的解决方案,根据你的需求选择:
方案1:使用服务账号(Service Account)授权(推荐)
这是最适合Android应用的方式,不需要用户交互,直接通过服务账号凭证调用API,完全避开桌面依赖。
步骤说明:
创建服务账号并获取密钥:
- 登录Google Cloud控制台,找到你的项目,进入「IAM与管理员」→「服务账号」
- 创建新服务账号,下载JSON格式的密钥文件,放到Android项目的
assets目录下 - 回到Google Play控制台,将该服务账号的邮箱添加为项目的开发者/所有者(确保有足够权限)
修改授权代码:
替换原来依赖AuthorizationCodeInstalledApp的代码,改用服务账号凭证构建AndroidPublisher实例:
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.androidpublisher.AndroidPublisher; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; import java.io.InputStream; import java.util.Arrays; public class AndroidPublisherHelper { private static final String APP_NAME = "你的应用名称"; private static final String PACKAGE_NAME = "你的应用包名"; // 按需调整权限,比如查看APK用AndroidPublisherScopes.ANDROIDPUBLISHER private static final String[] SCOPES = { com.google.api.services.androidpublisher.AndroidPublisherScopes.ANDROIDPUBLISHER }; public static AndroidPublisher getPublisherInstance() throws Exception { // 从Assets加载服务账号密钥 InputStream keyStream = YourApplication.getInstance().getAssets().open("service-account-key.json"); GoogleCredentials credentials = ServiceAccountCredentials.fromStream(keyStream) .createScoped(Arrays.asList(SCOPES)); return new AndroidPublisher.Builder(GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), new HttpCredentialsAdapter(credentials)) .setApplicationName(APP_NAME) .build(); } // 调用示例:列出指定编辑版本下的APK public static void fetchApkList(String editId) throws Exception { AndroidPublisher publisher = getPublisherInstance(); AndroidPublisher.Edits.Apks.List listRequest = publisher.edits().apks().list(PACKAGE_NAME, editId); AndroidPublisher.Edits.Apks.ListResponse response = listRequest.execute(); // 处理返回的APK数据,比如遍历response.getApks() for (AndroidPublisher.Edits.Apks.ListResponse.Apk apk : response.getApks()) { // 输出APK版本号、上传时间等信息 Log.d("PublisherAPI", "APK Version: " + apk.getVersionCode()); } } }
- 添加必要依赖:
在build.gradle(Module级)中添加以下依赖:
implementation 'com.google.apis:google-api-services-androidpublisher:v3-rev20240505-2.0.0' implementation 'com.google.auth:google-auth-library-oauth2-http:1.20.0' implementation 'com.google.api-client:google-api-client-android:1.34.1'
方案2:改用Android原生OAuth2授权流程(需用户交互)
如果你的业务必须让用户用自己的Google开发者账号授权,可以替换桌面版的授权逻辑,用Android系统的浏览器完成授权,再处理回调获取令牌。
关键修改点:
- 移除桌面依赖类:删掉
AuthorizationCodeInstalledApp和LocalServerReceiver的导入及使用 - 实现浏览器授权与回调:
- 配置AndroidManifest的Intent Filter,处理授权回调URL
- 用Intent打开授权页面,在回调中获取授权码并交换令牌
代码示例:
首先在AndroidManifest.xml中添加回调Activity的配置:
<activity android:name=".OAuthCallbackActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <!-- 替换成你自己的Scheme和Host --> <data android:scheme="com.your.app" android:host="oauth2callback" /> </intent-filter> </activity>
然后实现授权逻辑:
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow; import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.json.gson.GsonFactory; import com.google.api.client.util.store.AndroidDataStoreFactory; import com.google.api.services.androidpublisher.AndroidPublisher; import java.util.Arrays; public class OAuthHelper { private static final String CLIENT_ID = "你的OAuth客户端ID"; private static final String CLIENT_SECRET = "你的OAuth客户端密钥"; private static final String[] SCOPES = { com.google.api.services.androidpublisher.AndroidPublisherScopes.ANDROIDPUBLISHER }; public static final int REQUEST_OAUTH = 1001; public static void startOAuthAuthorization(Activity activity) throws Exception { GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), CLIENT_ID, CLIENT_SECRET, Arrays.asList(SCOPES)) .setDataStoreFactory(new AndroidDataStoreFactory(activity.getApplicationContext())) .setAccessType("offline") // 允许获取刷新令牌 .build(); // 生成授权URL,回调地址要和Manifest中的配置一致 String authUrl = flow.newAuthorizationUrl() .setRedirectUri("com.your.app:/oauth2callback") .build(); // 打开系统浏览器跳转授权页面 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)); activity.startActivityForResult(intent, REQUEST_OAUTH); } // 在调用Activity的onActivityResult中处理回调 public static void handleOAuthCallback(Intent data, Activity activity) throws Exception { String code = data.getData().getQueryParameter("code"); GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), CLIENT_ID, CLIENT_SECRET, Arrays.asList(SCOPES)) .setDataStoreFactory(new AndroidDataStoreFactory(activity.getApplicationContext())) .build(); // 交换授权码获取访问令牌 GoogleTokenResponse tokenResponse = flow.newTokenRequest(code) .setRedirectUri("com.your.app:/oauth2callback") .execute(); // 保存凭证,后续调用API使用 flow.createAndStoreCredential(tokenResponse, "user-id"); // 构建AndroidPublisher实例 AndroidPublisher publisher = new AndroidPublisher.Builder( GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), flow.createAndStoreCredential(tokenResponse, "user-id")) .setApplicationName("你的应用名称") .build(); // 接下来就可以调用API了,比如listApks } }
总结
- 优先选择服务账号方案:无需用户交互,代码更简洁,完全避开桌面依赖,适合Android应用后台调用API
- 用户授权方案:适合需要用户个人开发者权限的场景,但需要额外处理浏览器回调和令牌管理
内容的提问来源于stack exchange,提问作者Myoch




