所以我终于实现了用户选择在我尝试做oAuth2时使用哪个gmail帐户的能力……不幸的是,我有几个oAuth2问题没有得到回答…无论如何,在我单击登录按钮后,系统会提示我选择哪个gmail帐户的选项。但是,在我选择它并点击“确定”后,应用程序崩溃了。但是,我不确定为什么。
这是我的主要活动.java
public class MainActivity extends AppCompatActivity{
Context mContext = MainActivity.this;
private AccountManager mAccountManager;
private AuthPreferences authPreferences;
String[] avail_accounts;
ListView list;
ArrayAdapter<String> adapter;
EditText emailText;
TextView responseView;
ProgressBar progressBar;
SharedPreferences pref;
static final String API_KEY = "USE_YOUR_OWN_API_KEY";
static final String API_URL = "https://api.fullcontact.com/v2/person.json?";
static final String ClientId= "45471411055-m902j8c6jo4v6mndd2jiuqkanjsvcv6j.apps.googleusercontent.com";
static final String ClientSecret = "it5cGajZGSHQw5-e2kn2zL_R";
static final String SCOPE = "https://www.googleapis.com/auth/userinfo.email";
static final String AuthUrl = "https://accounts.google.com/o/oauth2/token";
private static final int AUTHORIZATION_CODE = 1993;
private static final int ACCOUNT_CODE = 1601;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
responseView = (TextView) findViewById(R.id.responseView);
emailText = (EditText) findViewById(R.id.emailText);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
final Context context = this;
mAccountManager = AccountManager.get(this);
authPreferences = new AuthPreferences(this);
SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button);
signInButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(authPreferences.getUser() != null && authPreferences.getToken() !=null)
{
doCoolAuthenticatedStuff();
}else
{
chooseAccount();
}
}
});
Button queryButton = (Button) findViewById(R.id.queryButton);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new RetrieveFeedTask().execute();
if(isNetworkAvailable()==true)
{
Intent intent = new Intent(context, NavDrawerActivity.class);
startActivity(intent);
}else {
Toast.makeText(MainActivity.this, "No Network Service, please check your WiFi or Mobile Data Connection", Toast.LENGTH_SHORT).show();
}
}
});
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
boolean dontShowDialog = sharedPref.getBoolean("DONT_SHOW_DIALOG", false);
if (!dontShowDialog) {
WifivsDataDialog myDiag = new WifivsDataDialog();
myDiag.show(getFragmentManager(), "WiFi");
myDiag.setCancelable(false);
}
}
private void doCoolAuthenticatedStuff()
{
Log.e("AuthApp", authPreferences.getToken());
}
private void chooseAccount()
{
Intent intent = AccountManager.newChooseAccountIntent(null, null,new String[] { "com.google"}, false, null, null, null, null);
startActivityForResult(intent, ACCOUNT_CODE);
}
private void requestToken()
{
Account userAccount = null;
String user = authPreferences.getUser();
for (Account account : mAccountManager.getAccountsByType("com.google")) {
if (account.name.equals(user)) {
userAccount = account;
break;
}
}
mAccountManager.getAuthToken(userAccount, "oauth2:" + SCOPE, null, this,
new OnTokenAcquired(), null);
}
private void invalidateToken()
{
AccountManager mAccountManager = AccountManager.get(this);
mAccountManager.invalidateAuthToken("com.google", authPreferences.getToken());
authPreferences.setToken(null);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == AUTHORIZATION_CODE) {
requestToken();
} else if (requestCode == ACCOUNT_CODE) {
String accountName = data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
authPreferences.setUser(accountName);
// invalidate old tokens which might be cached. we want a fresh
// one, which is guaranteed to work
invalidateToken();
requestToken();
}
}
}
private class OnTokenAcquired implements AccountManagerCallback<Bundle>
{
@Override
public void run(AccountManagerFuture<Bundle> result)
{
try {
Bundle bundle = result.getResult();
Intent launch = (Intent) bundle.get(AccountManager.KEY_INTENT);
if(launch != null)
{
startActivityForResult(launch, AUTHORIZATION_CODE);
} else {
String token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
authPreferences.setToken(token);
doCoolAuthenticatedStuff();
}
} catch (Exception e){
Log.e("ERROR", e.getMessage(), e);
}
}
}
public boolean isNetworkAvailable()
{
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isConnected())
{
Log.e("Network Testing", "Available");
return true;
}
Log.e("Network Testing", "Not Available");
return false;
}
class RetrieveFeedTask extends AsyncTask<Void, Void, String> {
private Exception exception;
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
responseView.setText("");
}
protected String doInBackground(Void... urls) {
String email = emailText.getText().toString();
// Do some validation here
try {
URL url = new URL(API_URL + "email=" + email + "&apiKey=" + API_KEY);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
finally{
urlConnection.disconnect();
}
}
catch(Exception e) {
Log.e("ERROR", e.getMessage(), e);
return null;
}
}
protected void onPostExecute(String response) {
if(response == null) {
response = "THERE WAS AN ERROR";
}
progressBar.setVisibility(View.GONE);
Log.i("INFO", response);
responseView.setText(response);
//
// TODO: check this.exception
// TODO: do something with the feed
// try {
// JSONObject object = (JSONObject) new JSONTokener(response).nextValue();
// String requestID = object.getString("requestId");
// int likelihood = object.getInt("likelihood");
// JSONArray photos = object.getJSONArray("photos");
// .
// .
// .
// .
// } catch (JSONException e) {
// e.printStackTrace();
// }
}
}
}
这是返回的错误。
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.jamessingleton.chffrapi, PID: 2025
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1601, result=-1, data=Intent { VirtualScreenParam=Params{mDisplayId=-1, null, mFlags=0x00000000)}(has extras) }} to activity {com.example.jamessingleton.chffrapi/com.example.jamessingleton.chffrapi.MainActivity}: java.lang.IllegalArgumentException: account is null
at android.app.ActivityThread.deliverResults(ActivityThread.java:4920)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4963)
at android.app.ActivityThread.access$1600(ActivityThread.java:221)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1848)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: java.lang.IllegalArgumentException: account is null
at android.accounts.AccountManager.getAuthToken(AccountManager.java:1267)
at com.example.jamessingleton.chffrapi.MainActivity.requestToken(MainActivity.java:152)
at com.example.jamessingleton.chffrapi.MainActivity.onActivityResult(MainActivity.java:181)
at android.app.Activity.dispatchActivityResult(Activity.java:7137)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4916)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4963)
at android.app.ActivityThread.access$1600(ActivityThread.java:221)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1848)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
如果任何人有任何想法,这将是非常感谢。此外,我还需要对所选的gmail帐户进行oAuth2。
这是我的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.jamessingleton.chffrapi">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>
<meta-data android:name="com.google.android.geo.API_KEY" android:value=""/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".NavDrawerActivity"
android:label="@string/title_activity_nav_drawer"
android:theme="@style/AppTheme.NoActionBar"></activity>
</application>
</manifest>
这是我的身份验证首选项.java
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
/**
* Created by James Singleton on 8/15/2016.
*/
public class AuthPreferences {
private static final String KEY_USER = "user";
private static final String KEY_TOKEN = "token";
private SharedPreferences preferences;
public AuthPreferences(Context context) {
preferences = context
.getSharedPreferences("auth", Context.MODE_PRIVATE);
}
public void setUser(String user) {
Editor editor = preferences.edit();
editor.putString(KEY_USER, user);
editor.commit();
}
public void setToken(String password) {
Editor editor = preferences.edit();
editor.putString(KEY_TOKEN, password);
editor.commit();
}
public String getUser() {
return preferences.getString(KEY_USER, null);
}
public String getToken() {
return preferences.getString(KEY_TOKEN, null);
}
}
所以我让它不会和下面的撞车
private void requestToken() {
Account userAccount = null;
String user = authPreferences.getUser();
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
for (Account account : mAccountManager.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE)) {
if (account.name.equals(user)) {
userAccount = account;
break;
}
}
mAccountManager.getAuthToken(userAccount, "oauth2:" + SCOPE, null, this, new OnTokenAcquired(), null);
}
但是,现在在我之后按允许之后,每当我单击登录按钮或打开应用程序时,它都会给我以下功能:
$ adb shell am start -n "com.example.jamessingleton.chffrapi/com.example.jamessingleton.chffrapi.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 23586 on device samsung-sm_g935v-0d75cc0d
D/RelationGraph: garbageCollect()
D/ContextRelationManager: ContextRelationManager() : FEATURE_ENABLED=true
W/ResourcesManager: getTopLevelResources: /data/app/com.example.jamessingleton.chffrapi-1/base.apk / 1.0 running in com.example.jamessingleton.chffrapi rsrc of package com.example.jamessingleton.chffrapi
I/InjectionManager: Inside getClassLibPath + mLibMap{0=, 1=}
D/ResourcesManager: For user 0 new overlays fetched Null
I/InjectionManager: Inside getClassLibPath caller
W/System: ClassLoader referenced unknown path: /data/app/com.example.jamessingleton.chffrapi-1/lib/arm64
W/art: Failed to open zip archive '/system/framework/dpmapi.jar': I/O Error
W/System: ClassLoader referenced unknown path: /data/app/com.example.jamessingleton.chffrapi-1/lib/arm64
I/FirebaseInitProvider: FirebaseApp initialization unsuccessful
D/InjectionManager: InjectionManager
D/InjectionManager: fillFeatureStoreMap com.example.jamessingleton.chffrapi
I/InjectionManager: Constructor com.example.jamessingleton.chffrapi, Feature store :{}
I/InjectionManager: featureStore :{}
W/ResourcesManager: getTopLevelResources: /data/app/com.example.jamessingleton.chffrapi-1/base.apk / 1.0 running in com.example.jamessingleton.chffrapi rsrc of package com.example.jamessingleton.chffrapi
D/RelationGraph: garbageCollect()
W/ResourcesManager: getTopLevelResources: /data/app/com.example.jamessingleton.chffrapi-1/base.apk / 1.0 running in com.example.jamessingleton.chffrapi rsrc of package com.example.jamessingleton.chffrapi
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
W/ResourcesManager: getTopLevelResources: /data/app/com.google.android.gms-2/base.apk / 1.0 running in com.example.jamessingleton.chffrapi rsrc of package com.google.android.gms
D/ResourcesManager: For user 0 new overlays fetched Null
I/InjectionManager: Inside getClassLibPath caller
D/ChimeraCfgMgr: Reading stored module config
W/System: ClassLoader referenced unknown path: /data/user/0/com.google.android.gms/app_chimera/m/00000007/n/arm64-v8a
D/ChimeraFileApk: Primary ABI of requesting process is arm64-v8a
D/ChimeraFileApk: Classloading successful. Optimized code found.
D/Activity: performCreate Call Injection manager
I/InjectionManager: dispatchOnViewCreated > Target : com.example.jamessingleton.chffrapi.WifivsDataDialog isFragment :true
D/SecWifiDisplayUtil: Metadata value : SecSettings2
D/ViewRootImpl: #1 mView = com.android.internal.policy.PhoneWindow$DecorView{527c722 V.E...... R.....I. 0,0-0,0}
D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
I/InjectionManager: dispatchOnViewCreated > Target : com.example.jamessingleton.chffrapi.MainActivity isFragment :false
D/ViewRootImpl: #1 mView = com.android.internal.policy.PhoneWindow$DecorView{6e855b3 I.E...... R.....ID 0,0-0,0}
I/Adreno: QUALCOMM build : c0299d7, I241dab1ec4
Build Date : 01/25/16
OpenGL ES Shader Compiler Version: XE031.06.00.05
Local Branch :
Remote Branch : refs/tags/AU_LINUX_ANDROID_LA.HB.1.1.1.06.00.01.063.117
Remote Branch : NONE
Reconstruct Branch : NOTHING
D/libEGL: eglInitialize EGLDisplay = 0x7f56654188
I/OpenGLRenderer: Initialized EGL, version 1.4
I/InjectionManager: dispatchCreateOptionsMenu :com.example.jamessingleton.chffrapi.MainActivity
I/InjectionManager: dispatchPrepareOptionsMenu :com.example.jamessingleton.chffrapi.MainActivity
W/DisplayListCanvas: DisplayListCanvas is started on unbinded RenderNode (without mOwningView)
D/libGLESv1: DTS_GLAPI : DTS is not allowed for Package : com.example.jamessingleton.chffrapi
W/DisplayListCanvas: DisplayListCanvas is started on unbinded RenderNode (without mOwningView)
D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 96 - 0, 0) vi=Rect(0, 96 - 0, 0) or=1
I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@d427800 time:21109211
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
I/WifiManager: isAllowWifiWarning() -> isCscWifiEnableWarning : false ChinaNalSecurityType :
D/ViewRootImpl: #3 mView = null
E/ViewRootImpl: sendUserActionEvent() mView == null
D/ViewRootImpl: MSG_RESIZED: ci=Rect(0, 96 - 0, 1128) vi=Rect(0, 96 - 0, 1128) or=1
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
W/IInputConnectionWrapper: getCursorCapsMode on inactive InputConnection
W/IInputConnectionWrapper: getCursorCapsMode on inactive InputConnection
W/IInputConnectionWrapper: getExtractedText on inactive InputConnection
W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
V/ActivityThread: updateVisibility : ActivityRecord{6cf7f64 token=android.os.BinderProxy@d427800 {com.example.jamessingleton.chffrapi/com.example.jamessingleton.chffrapi.MainActivity}} show : true
W/IInputConnectionWrapper: getSelectedText on inactive InputConnection
W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper: getExtractedText on inactive InputConnection
W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection
D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 96 - 0, 0) vi=Rect(0, 96 - 0, 0) or=1
I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@d427800 time:21240808
D/ViewRootImpl: MSG_RESIZED: ci=Rect(0, 96 - 0, 1128) vi=Rect(0, 96 - 0, 1128) or=1
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
D/ViewRootImpl: ViewPostImeInputStage processPointer 0
D/ViewRootImpl: ViewPostImeInputStage processPointer 1
E/AuthApp: ya29.Ci9BA9J58MhaacpZQ7xiX08Br6gX1cMOTmoCPSqkQeml2LEh6GIBxVenks9tXee1kQ
V/ActivityThread: updateVisibility : ActivityRecord{6cf7f64 token=android.os.BinderProxy@d427800 {com.example.jamessingleton.chffrapi/com.example.jamessingleton.chffrapi.MainActivity}} show : false
Application terminated.
Java的驱动API客户端库调用GoogleAuthUtil.getToken(),这需要GET_ACCOUNTS权限。您需要在清单文件中拥有该权限。
我的应用程序中有以下工作流: 用户登录我的自定义应用程序 用户点击一个按钮链接他们的YouTube帐户 应用程序使用下面的代码列表发出服务器端请求 用户被重定向到google auth url 此时,发生了两件事之一: [我从来不想要这种行为] - 如果用户只登录了一个谷歌帐户(即mail,谷歌域名应用套件等),则永远不会要求用户选择要链接的帐户。它只是假设他们想要使用他们登录的那个,并继续其快乐
我有一个<代码>材料数据包< /代码>,它选择了一系列数据,例如从<代码> 2021年1月1日到2021年1月31日< /代码>。 打开MaterialDatePicker时,会显示当前日期。当我尝试从2月滚动到1月时,一个月的最后一天是不可见的 要选择本月的最后一天,我应该向下滚动,但当我选择本月的最后一天时,应用程序崩溃,显示此错误: java.lang.NullPointerExcture:
我们的应用程序具有SMTP功能,允许用户将Gmail连接到OAuth2,如果帐户是Google工作区类型,则此功能很好,但如果我们尝试连接到个人Gmail帐户,OAuth2会显示“此应用程序被阻止”错误,如下图所示。 有什么想法吗? 注意:如果连接Google Workspace帐户,我们的代码工作正常,只是在尝试连接个人Google Gmail帐户时有这个问题。
在我的 Web 应用程序中,我想实现以程 用户点击使用Google按钮登录 用户在重定向屏幕中选择帐户 我收到一个JWT,其中包含帐户ID和电子邮件地址 我将帐户ID设置为登录提示,并仅设置“同意”提示 我创建Auth URL并再次重定向到Google以获得同意 在下一个同意屏幕中,用户应该只需要批准同意,而不是第二次选择他的帐户 我处理来自同意的回调 根据文档,我实现了“使用Google按钮登录
我正在创建一个呼叫阻止应用程序,当我添加复选框或单选按钮到我的布局,应用程序开始崩溃。 活动代码。 } 广播接收机代码 公共void onReceive(上下文、意图){ XML文件如下所示 错误日志如下
我正在尝试了解如何在我的Android应用程序(使用Android Studio)中集成Google Drive API。我已经尝试了我在这里找到的示例应用程序(https://github.com/googleworkspace/android-samples/tree/master/drive/deprecation),但是在Google API控制台配置之后,当我选择帐户时,我的应用程序陷入