You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使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,完全避开桌面依赖。

步骤说明:

  1. 创建服务账号并获取密钥

    • 登录Google Cloud控制台,找到你的项目,进入「IAM与管理员」→「服务账号」
    • 创建新服务账号,下载JSON格式的密钥文件,放到Android项目的assets目录下
    • 回到Google Play控制台,将该服务账号的邮箱添加为项目的开发者/所有者(确保有足够权限)
  2. 修改授权代码
    替换原来依赖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());
        }
    }
}
  1. 添加必要依赖
    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系统的浏览器完成授权,再处理回调获取令牌。

关键修改点:

  1. 移除桌面依赖类:删掉AuthorizationCodeInstalledAppLocalServerReceiver的导入及使用
  2. 实现浏览器授权与回调
    • 配置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

火山引擎 最新活动