本文写一些其它方面的应用.
public interface AuthApi {
@Headers("Content-Type: application/json")
@POST("https://www.youtube.com/o/oauth2/device/code")
Call<UserCode> getUserCode(@Body String authQuery);
@Headers("Content-Type: application/json")
@POST("https://www.youtube.com/o/oauth2/token")
Call<RefreshToken> getRefreshToken(@Body String authQuery);
@Headers("Content-Type: application/json")
@POST("https://www.youtube.com/o/oauth2/token")
Call<AccessToken> getAccessToken(@Body String authQuery);
@Headers("Content-Type: application/json")
@POST("https://www.youtube.com/youtubei/v1/account/accounts_list")
Call<AccountsList> getAccountsList(@Body String authQuery);
}
这是接口的声明.然后直接用它就可以了.申请key这些就不详细说了.
本文主要是涉及tv版本的开发,tv与手机不同,如果使用app-auth上的认证过程,在tv上,会因为多数摇控器无法点击而失败,有些遥控器是可以出现鼠标的.
谷歌官方提供了一种tv 认证的方式,申请凭据的时候,要选tv,官方文档也有相关的说明.最近youtube的官方文档已经没有了示例了,前一周变的...
public class AuthApiHelper {
private static final String USER_CODE = "{\"client_id\":\"%s\",\"device_id\":\"%s\",\"model_name\":\"%s\",\"scope\":\"%s\"}";
private static final String REFRESH_TOKEN = "{\"code\":\"%s\",\"client_id\":\"%s\",\"client_secret\":\"%s\",\"grant_type\":\"%s\"}";
private static final String ACCESS_TOKEN = "{\"refresh_token\":\"%s\",\"client_id\":\"%s\",\"client_secret\":\"%s\",\"grant_type\":\"%s\"}";
//private static final String APP_SCOPE = "http://gdata.youtube.com https://www.googleapis.com/auth/youtube-paid-content";
private static final String GRANT_TYPE_DEFAULT = "http://oauth.net/grant_type/device/1.0";
private static final String GRANT_TYPE_REFRESH = "refresh_token";
private static final String MODEL_NAME = "ytlr::";
//public static String getAccountsListQuery() {
// return ServiceHelper.createQueryTV("\"accountReadMask\":{\"returnOwner\":true,\"returnBrandAccounts\":true,\"returnPersonaAccounts\":false}");
//}
public static String getUserCodeQuery(String clientId) {
return String.format(USER_CODE, clientId, MediaServiceData.instance().getDeviceId(), MODEL_NAME, "openid email profile https://www.googleapis.com/auth/youtube");
}
public static String getRefreshTokenQuery(String deviceCode, String clientId, String clientSecret) {
return String.format(REFRESH_TOKEN, deviceCode, clientId, clientSecret, GRANT_TYPE_DEFAULT);
}
public static String getAccessTokenQuery(String refreshToken, String clientId, String clientSecret) {
return String.format(ACCESS_TOKEN, refreshToken, clientId, clientSecret, GRANT_TYPE_REFRESH);
}
}
这段代码就是设置了请示内容,scope要email, profile与youtube,前面两个是得到邮箱,用户名信息.后面是访问youtube的内容.
但是,认证过程,发现了,没有得到用户信息,只得到了邮箱,是在idtoken里面的.
Call<UserCode> wrapper = mAuthApi.getUserCode(
AuthApiHelper.getUserCodeQuery(clientId)
);
这是调用认证的方法.
开始认证了.UserCode userCodeResult = mAuthService.getUserCode();
在rxjava里面容易实现,这个调用成功后就调用onnext.然后接着出现什么呢?就是让手机去打开相应的地址,进行认证.这个手机的地址应该是什么样的
private static final String SIGN_IN_URL_FULL = "https://youtube.com/tv/activate"; // support query params
private void updateUI(String userCode, String url) {
if (TextUtils.isEmpty(userCode)) {
return;
}
user_code.setText(userCode);
Glide.with(this)
.load(Utils.toQrCodeLink(SIGN_IN_URL_FULL + "?user_code=" + userCode.replace(" ", "-")))
//.load(Utils.toQrCodeLink(url))
.apply(ViewUtil.glideOptions()).error(ContextCompat.getDrawable(this, R.drawable.activate_account_qrcode))
//.listener(mErrorListener)
.into(img_code);
}
上面得到的usecode得到,里面会有一个code,这个code是用于手机认证里面的输入框中的内容,这里的方式是生成一个二维码,然后手机一扫,就直接过去了.二维码的生成
private static final String QR_CODE_URL_TEMPLATE = "https://api.qrserver.com/v1/create-qr-code/?data=%s";data就是链接内容
可以参考官方文档与二维码的图片,最终展示出来就可以了.
展示后的逻辑,官方文档说明,刷新token的接口,直到得到token. 上面拼接的地址可以不使用这个url,使用另一个SIGN_IN_URL_FULL,这个可以带参数 ,把code带过去,否则用户还要手输入
刷新token就是上面api中的getRefreshToken接口.传的参数oauth2都一样.大概就是private static final String REFRESH_TOKEN = "{\"code\":\"%s\",\"client_id\":\"%s\",\"client_secret\":\"%s\",\"grant_type\":\"%s\"}";这样的东西了.
手机是没有client_secret,但web与tv是有的.
如果手机扫码后一直没有登录,那么这个接口刷不到数据.
有了token,用户数据是如何获取的.smarttube里面是通过getAccountsList,这个比较复杂,有更简单的方法.
private boolean getUserInfo(String accessToken, YouTubeAccount account) {
try {
String url = "https://openidconnect.googleapis.com/v1/userinfo";
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(CONNECTION_TIMEOUT_MS);
conn.setReadTimeout(READ_TIMEOUT_MS);
conn.setInstanceFollowRedirects(false);
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
conn.setInstanceFollowRedirects(false);
String response = Okio.buffer(Okio.source(conn.getInputStream())).readString(StandardCharsets.UTF_8);
Log.d(TAG, "user:" + response);
JSONObject jo = new JSONObject(response);
account.setEmail(jo.optString("email"));
account.setName(jo.optString("name"));
account.setImageUrl(jo.optString("picture"));
return true;
} catch (IOException ioEx) {
Log.e(TAG, "Network error when querying userinfo endpoint", ioEx);
} catch (Exception jsonEx) {
Log.e(TAG, "Failed to parse userinfo response");
}
return false;
}
这个接口就是app-auth里面获取用户信息得到的,本来想的是idtoken解析一下,它是ba
se64编码,但发现上面token里面的idtoken并没有包含到这些东西,只有邮箱.
而这个接口可以有邮箱,用户名,头像等
在smarttube中,使用了200次循环.
到这里,在tv上认证,得到token,通过token,得到用户信息的整个过程就完成了.
剩下的就是使用这个token.但只有一个小时的时效,所以在每次调用接口前去检测一下是否超时.这是个缺点
smarttube,在github上有源码,
后续会写一些关于tv上如何使用leanback这个库,做一个简单实用的tv应用