前言
由于业务上的需要,想要在android端实现Google登录。但是android的原生方法受到限制,实现起来比较麻烦。于是想到了一个曲线救国的方法,在android端使用Google的web登录。
实现逻辑
在andorid端拉起外部浏览器,用户登录Google账号,登录成功后,再将登录信息返回到app中。
这里需要注意,必须要跳转到外部浏览器,不能使用android自带的webview。因为google官方已经禁止了这种行为。如下图:
实现步骤
创建一个
google-login.html
文件,使用Google OAuth
登录,代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Google 登录</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
background-color: #000;
color: #fff;
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
}
button {
padding: 12px 24px;
font-size: 16px;
border-radius: 8px;
border: none;
background-color: #4285f4;
color: white;
cursor: pointer;
margin-top: 16px;
}
#status {
margin-top: 20px;
font-size: 14px;
color: #0f0;
}
</style>
</head>
<body>
<h2>使用 Google 登录</h2>
<button onclick="loginWithGoogle()">登录</button>
<div id="status"></div>
<script>
const clientId = '你谷歌登录的客户端id';
function loginWithGoogle() {
const redirectUri = encodeURIComponent('https://www.projectdtest.com/oauth2callback.html');
const scope = encodeURIComponent('profile email openid');
const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?` +
`client_id=${clientId}&` +
`redirect_uri=${redirectUri}&` +
`response_type=token&` +
`scope=${scope}`;
window.location.href = authUrl;
}
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get("google_token");
if (token) {
document.getElementById("status").innerText = "登录成功,正在拉取用户信息...";
fetchUserInfo(token).then(userInfo => {
document.getElementById("status").innerText = `欢迎你,${userInfo.name || userInfo.email}`;
const message = {
type: 'google_login',
token: token,
user: userInfo
};
if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
window.ReactNativeWebView.postMessage(JSON.stringify(message));
} else if (window.AndroidInterface && window.AndroidInterface.onReceiveToken) {
window.AndroidInterface.onReceiveToken(JSON.stringify(message));
} else if (window.parent !== window) {
window.parent.postMessage(JSON.stringify(message), '*');
} else {
console.log("Token & 用户信息:", message);
}
}).catch(err => {
document.getElementById("status").innerText = "用户信息拉取失败";
console.error("用户信息错误", err);
});
}
async function fetchUserInfo(token) {
const res = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
headers: {
Authorization: `Bearer ${token}`
}
});
if (!res.ok) throw new Error("Google 用户信息获取失败");
return await res.json();
}
</script>
</body>
</html>客户端id需要去
https://console.cloud.google.com/
获取,如下图:创建一个
oauth2callback.html
,用来将google登录成功后返回的token和用户信息返回到app中。代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Google 登录回调</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script>
async function fetchUserInfo(token) {
const res = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
headers: {
Authorization: `Bearer ${token}`
}
});
if (!res.ok) throw new Error("获取用户信息失败");
return await res.json();
}
(async () => {
const hash = window.location.hash.substring(1);
const params = new URLSearchParams(hash);
const token = params.get("access_token");
console.log("Access Token:", token);
if (token) {
try {
const user = await fetchUserInfo(token);
console.log("用户信息:", user);
const scheme = `yourApp://google-login` +
`?google_token=${encodeURIComponent(token)}` +
`&id=${encodeURIComponent(user.id || '')}` +
`&email=${encodeURIComponent(user.email || '')}` +
`&name=${encodeURIComponent(user.name || '')}` +
`&picture=${encodeURIComponent(user.picture || '')}`;
window.location.href = scheme;
} catch (err) {
document.body.innerText = '用户信息获取失败,请重试';
console.error(err);
}
} else {
document.body.innerText = 'Google 登录失败,请重试';
}
})();
</script>
</body>
</html>将上面2个文件放在服务器上,在后台相应位置配置好即可。配置如下图:
修改
App
的AndroidManifest.xml
注册 URL scheme:1
2
3
4
5
6
7
8
9
10<activity android:name=".AppActivity"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="yourApp" android:host="google-login" />
</intent-filter>
</activity>注意:这里的相关信息要改成你自己的。特别是
android:scheme
和android:host
要和oauth2callback.html
中的scheme
和host
保持一致。不然在web登录成功后无法唤起App。在
App
中接收回调数据。
5.1 在工程中新增一个BrowserCallback
类,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41package com.a.b ; // 注意这里要改成你自己的包名
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import com.cocos.lib.CocosHelper;
import com.cocos.lib.CocosJavascriptJavaBridge;
public class BrowserCallback {
private static final String TAG = "BrowserCallback";
private static BrowserCallback instance = null;
public static BrowserCallback getInstance() {
if (instance == null) {
instance = new BrowserCallback();
}
return instance;
}
public void handleIntent(Intent intent) {
Uri uri = intent.getData();
if (uri != null && "ronaldoapp".equals(uri.getScheme()) && "google-login".equals(uri.getHost())) {
String token = uri.getQueryParameter("google_token");
String email = uri.getQueryParameter("email");
String id = uri.getQueryParameter("id");
String name = uri.getQueryParameter("name");
String picture = uri.getQueryParameter("picture");
String json = String.format("{\"token\":\"%s\", \"email\":\"%s\", \"id\":\"%s\", \"name\":\"%s\", \"picture\":\"%s\"}",
token, email, id, name, picture);
Log.d(TAG, "handleIntent: " + json);
CocosHelper.runOnGameThread(() -> {
String js = String.format("window.onGoogleLogin && window.onGoogleLogin(%s)", json);
CocosJavascriptJavaBridge.evalString(js);
});
}
}
}
5.2 在App
的AppActivity
中注册BrowserCallback
在onCreate
方法中添加下面代码:
1 | BrowserCallback.getInstance().handleIntent(getIntent()); // 处理首次唤起 |
再在AppActivity
中添加下面代码:
1 |
|
总结
到这里整个登录流程就完成了。
如果你相关参数没有配置错的话,使用我的这套代码是可以实现Google登录的。