[英]Google picker auth popup is being blocked
我有一個列出工作的移動網站,用戶申請並上傳他們的簡歷(簡歷) - 我希望他們能夠從他們的Google雲端硬盤中選擇一個文件。
我在這里創建了Hello world示例 - https://developers.google.com/picker/docs/ (為方便起見,此處轉載的代碼)
問題是,如果尚未登錄到雲端硬盤,則會啟動登錄彈出窗口。 這在桌面上已經夠糟了,但在手機上真的很糟糕。
我試過這個解決方案 ,但得到'TypeError:gapi.auth is undefined'
我還嘗試從onclick事件啟動選擇器,而不是文檔描述的onload。
function launchDrive()
{
gapi.load('auth', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
}
<input type='button' value='Launch Drive' onclick='launchDrive();'>
Google代碼示例:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Picker Example</title>
<script type="text/javascript">
var developerKey = 'xxxxxxxYYYYYYYY-12345678';
var clientId = "1234567890-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com"
var scope = ['https://www.googleapis.com/auth/photos'];
var pickerApiLoaded = false;
var oauthToken;
function onApiLoad() {
gapi.load('auth', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
}
function onAuthApiLoad() {
window.gapi.auth.authorize(
{
'client_id': clientId,
'scope': scope,
'immediate': false
},
handleAuthResult);
}
function onPickerApiLoad() {
pickerApiLoaded = true;
createPicker();
}
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
createPicker();
}
}
// Create and render a Picker object for picking user Photos.
function createPicker() {
if (pickerApiLoaded && oauthToken) {
var picker = new google.picker.PickerBuilder().
addView(google.picker.ViewId.PHOTOS).
setOAuthToken(oauthToken).
setDeveloperKey(developerKey).
setCallback(pickerCallback).
build();
picker.setVisible(true);
}
}
// A simple callback implementation.
function pickerCallback(data) {
var url = 'nothing';
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
url = doc[google.picker.Document.URL];
}
var message = 'You picked: ' + url;
document.getElementById('result').innerHTML = message;
}
</script>
</head>
<body>
<div id="result"></div>
<!-- The Google API Loader script. -->
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>
2015年5月13日編輯
繼Jason的回答之后,這也是我也嘗試過的(通過oncllick按鈕調用):
function launchDrive()
{
//gapi.load('auth', {'callback': onAuthApiLoad});
gapi.auth.init(onAuthApiLoad);
gapi.load('picker', {'callback': onPickerApiLoad});
}
您將要調用gapi.auth.init。 請參閱此處的文檔: https : //developers.google.com/api-client-library/javascript/reference/referencedocs#gapiauthinit
初始化授權功能。 在客戶端加載時調用此方法以防止彈出窗口阻止程序阻塞gapi.auth.authorize調用上的auth窗口。
我現在有工作。
在選擇器的示例中, https : //developers.google.com/picker/docs/ ,它調用:
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
在此示例中, https : //developers.google.com/api-client-library/javascript/start/start-js ,它調用:
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
使用client.js修復了'TypeError:gapi.auth is undefined'問題,因此登錄彈出窗口工作正常。
也許api.js是API的舊版本?
要解決您的問題,您需要了解google如何在您的案例中執行oauth:
為什么瀏覽器在第二步阻止彈出窗口:
window.event
被破壞)。 因此,如果用戶沒有阻止彈出窗口並且您的彈出窗口仍然被阻止,則gapi操作看起來像:
<input type="button" onclick="auth" value="click"/>
function auth() {
setTimeout(function() {
// by this time window.event is destroyed, that's why browser blocks the popup
window.open(document.URL, '_blank', 'location=yes,height=570,width=520,scrollbars=yes,status=yes');
}, 100)
}
所以你應該做的:
window.event
將不為null。 所以將所有gapi init方法移動到DOMContentLoaded
。 只是跳到底部
這是目前適用於我的代碼。 這是我使用這個API的第一個小時,所以我真的不知道這些函數是做什么的,我也不知道正確的順序和錯誤處理是什么,但至少現在這個功能正常。 也許它將來會幫助別人。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Picker Example</title>
</head>
<body style="width: 70%; margin: 100px auto;">
<!-- Added a button to open picker -->
<button onclick="loadPicker();" >Open from GoogleDrive</button>
<div id="result"></div>
<!-- Moved to end of body tag instead of head -->
<script type="text/javascript">
// The Browser API key obtained from the Google API Console.
// Replace with your own Browser API key, or your own key.
var developerKey = '<IDK WHAT'S SUPPOSED TO GO HERE, BUT ITS OK>';
// The Client ID obtained from the Google API Console. Replace with your own Client ID.
var clientId = "<YOUR CLIENT ID GOES HERE>.apps.googleusercontent.com"
// Replace with your own project number from console.developers.google.com.
// See "Project number" under "IAM & Admin" > "Settings"
var appId = "<YOUR APP ID GOES HERE>";
// Scope to use to access user's Drive items.
var scope = ['https://www.googleapis.com/auth/drive'];
var pickerApiLoaded = false;
var oauthToken;
// Use the Google API Loader script to load the google.picker script.
function loadPicker() {
// This needs to be client:auth2 no client
gapi.load('client:auth2', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
}
function onAuthApiLoad() {
// we need to init gapi.client with the clientId and scope first
gapi.client.init({
clientId: clientId,
scope: scope
});
// Now we can authorize? seems like the same thing here
window.gapi.auth.authorize(
{
'client_id': clientId,
'scope': scope,
'immediate': false
},
handleAuthResult);
}
function onPickerApiLoad() {
pickerApiLoaded = true;
createPicker();
}
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
createPicker();
}
}
// Create and render a Picker object for searching images.
function createPicker() {
// Wow this is a mess
if (pickerApiLoaded && oauthToken) {
var view = new google.picker.View(google.picker.ViewId.DOCS);
view.setMimeTypes("image/png,image/jpeg,image/jpg");
var picker = new google.picker.PickerBuilder()
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.setAppId(appId)
.setOAuthToken(oauthToken)
.addView(view)
.addView(new google.picker.DocsUploadView())
// Guess this is... optional?
//.setDeveloperKey(developerKey)
.setCallback(pickerCallback)
.build();
picker.setVisible(true);
}
}
// A simple callback implementation.
function pickerCallback(data) {
if (data.action == google.picker.Action.PICKED) {
var fileId = data.docs[0].id;
alert('Selected fileId: ' + fileId);
}
}
</script>
<!-- The Google API Loader script. Removed the autorun -->
<script type="text/javascript" src="https://apis.google.com/js/api.js"></script>
</body>
</html>
編輯:如果出現一個無法加載的彈出窗口,只需將其關閉並再次單擊該按鈕即可。 這解決了我剛才遇到的另一個問題。
再一次,我不知道我在做什么,所以希望我能更好地理解這一點,並在以后澄清事情。
E2:啊,關於OAuth2的更多信息可以在Javascript GAPI文檔頁面上找到,可以在這里找到: https : //developers.google.com/api-client-library/javascript/features/authentication
從另一個文檔看,如果尚未加載, gapi.load('client', callback)
將加載auth2。 調用gapi.load('client:auth2', callback)
將只保存1個網絡請求。
注意:使用Oauth 2.0授權應用程序時,您不需要像第一個示例中那樣設置API密鑰。 但是,這樣做是一種很好的做法,以防您的代碼擴展以處理未經授權的請求。
這就解釋了為什么我可以刪除API /開發人員密鑰。
編輯3:好的,上面的代碼在技術上是錯誤的。
警告:不要在推薦的gapi.auth2.init和signIn流程旁邊使用此方法。 這是兩個不同的行為(gapi.auth2.authorize的授權與gapi.auth2.init / signIn的身份驗證),如果在同一個應用程序中使用,則會出現意外問題。
autorize用於單次使用身份驗證(例如,如果您登錄了2個Google帳戶)。 雖然使用gapi.init()
是為了更長期的會話(比如登錄和退出網站)。
目前這是如何工作的,我不知道。
不要使用上面的代碼,只是想記錄進度。 這是一個使用getAuthResponse()
的更好的演示
<html>
<head></head>
<body>
<div style="padding: 50px">
<h2 style="color: #2196f3;">Status: <span id='status'></span></h2>
<button id="signin-button" onclick="handleSignInClick()">Sign In</button>
<button id="signout-button" onclick="handleSignOutClick()">Sign Out</button>
<button id="signout-button" onclick="openFile()">Open File</button>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
var cid = '<CLIENTID_HERE>';
var scope = 'https://www.googleapis.com/auth/drive';
var authenticated = false;
var pickerLoaded = false;
var auth = null;
var user = null;
var response = null;
var token = null;
var stat = $('#status');
function openFile() {
gapi.load('client:auth2', initClient);
gapi.load('picker', onPickerLoad);
}
function initClient() {
stat.html("starting");
gapi.client.init({
clientId: cid,
scope: scope
}).then(
function () {
console.log("init");
// Check if we are logged in.
auth = gapi.auth2.getAuthInstance();
auth.isSignedIn.listen(onStatusChange);
authenticated = auth.isSignedIn.get();
stat.html(authenticated);
if (authenticated) {
stat.html("Logged In!");
user = auth.currentUser.get();
response = user.getAuthResponse(true);
token = response.access_token;
showPicker();
} else {
stat.html("Logged Out!");
}
}, function(){stat.html("error")});
}
function onStatusChange(isSignedIn) {
if (isSignedIn) {
stat.html("Logged In!");
authenticated = true;
user = auth.currentUser.get();
response = user.getAuthResponse(true);
token = response.access_token;
showPicker();
showPicker();
} else {
authenticated = false;
stat.html("Logged Out!");
}
}
function handleSignInClick(event) {
gapi.auth2.getAuthInstance().signIn();
}
function handleSignOutClick(event) {
gapi.auth2.getAuthInstance().signOut();
alert("signed out");
}
function onPickerLoad() {
pickerLoaded = true;
showPicker();
}
function showPicker() {
if (pickerLoaded && authenticated) {
var view = new google.picker.View(google.picker.ViewId.DOCS);
var picker = new google.picker.PickerBuilder();
picker.addView(view);
picker.enableFeature(google.picker.Feature.MULTISELECT_ENABLED);
picker.setOAuthToken(token);
picker.setAppId()
picker.setCallback(onDriveFileOpen);
picker = picker.build();
picker.setVisible(true);
}
}
function onDriveFileOpen(data) {
console.log(data);
if (data.action == google.picker.Action.PICKED) {
var fileId = data.docs[0].id;
console.log(fileId);
alert(data.docs[0].name);
}
}
</script>
<script async defer src="https://apis.google.com/js/api.js">
</script>
</body>
</html>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.