调用GoogleNetHTTPTransport时出现‘JKS not found’错误求助
Hey there! Let's break down your issue step by step, since you're new to Google's authentication and API ecosystem.
1. Why You're Seeing the KeyStoreException
The error java.security.KeyStoreException: JKS not found happens because Android doesn't use the JKS (Java KeyStore) format by default—it relies on BKS (Bouncy Castle KeyStore) or the system's built-in trust store instead.
When you call GoogleNetHttpTransport.newTrustedTransport(), it tries to load a JKS-formatted trust store to verify the authenticity of Google's servers during HTTPS connections. Since this file doesn't exist on Android, the method throws that exception.
To clarify: The KeyStore here acts as a secure repository for trusted CA (Certificate Authority) certificates. It ensures that when your app connects to Google's APIs, it's talking to a legitimate Google server, not a malicious imposter.
2. The Fix: Use Android-Compatible HTTP Transport
Google provides a dedicated transport for Android apps that works with the system's native trust store. Here's how to fix your code:
Step 1: Replace the Transport Instance
Instead of GoogleNetHttpTransport.newTrustedTransport(), use AndroidHttp.newCompatibleTransport(). This method is designed to work seamlessly with Android's security infrastructure.
Step 2: Update Your Imports
Make sure you add this import at the top of your file:
import com.google.api.client.extensions.android.http.AndroidHttp;
Step 3: Modify the Flow Builder
Update the part where you build the GoogleAuthorizationCodeFlow to use the Android-compatible transport:
flow = new GoogleAuthorizationCodeFlow .Builder(AndroidHttp.newCompatibleTransport(), JacksonFactory.getDefaultInstance(), clientSecrets, scopes) .setDataStoreFactory(new MemoryDataStoreFactory()) .setAccessType("offline") .build();
3. Code Optimization Tips
Your current code works but can be tightened up for reliability and maintainability:
a. Use Try-With-Resources for Input Streams
Your InputStream and Reader aren't being closed, which can cause memory leaks. Use try-with-resources to auto-close them:
try (InputStream jsonInput = resources.openRawResource(R.raw.credential_info); Reader credentialReader = new InputStreamReader(jsonInput)) { Log.v("GoogleAut", "credential reader created"); clientSecrets = GoogleClientSecrets.load(JacksonFactory.getDefaultInstance(), credentialReader); } catch (IOException e) { e.printStackTrace(); Log.v("ERROR GoogleAut","Failed to load client secrets"); }
b. Improve Error Handling
Avoid catching generic Exception—catch specific exceptions to handle them more precisely. For example, instead of catching Exception in the final authorize call, catch IOException and GeneralSecurityException separately.
c. Avoid Redundant Null Checks
resources.openRawResource(R.raw.credential_info) won't return null if the resource exists (it'll throw a NotFoundException if it's missing). You can remove the redundant NullPointerException catch block and handle NotFoundException instead.
d. Persist Credentials (Optional)
MemoryDataStoreFactory stores credentials only in memory, so your app will re-authenticate every time it restarts. For a better user experience, use a persistent data store like SharedPreferencesDataStoreFactory (from the com.google.api-client:google-api-client-android library).
Modified Full authorize() Method
Here's your updated code with all the fixes and optimizations:
private Credential authorize(Context context) { GoogleClientSecrets clientSecrets = null; // Load client secrets with auto-closing streams try (InputStream jsonInput = context.getResources().openRawResource(R.raw.credential_info); Reader credentialReader = new InputStreamReader(jsonInput)) { Log.v("GoogleAut", "Credential reader created"); clientSecrets = GoogleClientSecrets.load(JacksonFactory.getDefaultInstance(), credentialReader); } catch (Resources.NotFoundException e) { e.printStackTrace(); Log.v("ERROR GoogleAut", "Credential resource not found"); } catch (IOException e) { e.printStackTrace(); Log.v("ERROR GoogleAut", "Failed to read credential file"); } if (clientSecrets == null) { Log.v("ERROR GoogleAut", "Client secrets could not be loaded"); return null; } List<String> scopes = Arrays.asList(SheetsScopes.SPREADSHEETS); GoogleAuthorizationCodeFlow flow = null; try { flow = new GoogleAuthorizationCodeFlow .Builder(AndroidHttp.newCompatibleTransport(), JacksonFactory.getDefaultInstance(), clientSecrets, scopes) .setDataStoreFactory(new MemoryDataStoreFactory()) .setAccessType("offline") .build(); } catch (IOException e) { e.printStackTrace(); Log.v("ERROR GoogleAut", "IOException during flow creation"); } catch (GeneralSecurityException e) { e.printStackTrace(); Log.v("ERROR GoogleAut", "Security exception during flow creation"); } if (flow == null) { Log.v("ERROR GoogleAut", "Authorization flow could not be built"); return null; } try { return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()) .authorize("user"); } catch (IOException e) { e.printStackTrace(); Log.v("ERROR GoogleAut", "IO error during authorization"); } catch (GeneralSecurityException e) { e.printStackTrace(); Log.v("ERROR GoogleAut", "Security error during authorization"); } Log.v("ERROR GoogleAut", "Authorization failed"); return null; }
内容的提问来源于stack exchange,提问作者Juanse Hevia

