Ведется много дискуссий о том, что Google не предоставляет Java (и другой) API для доступа к своим каналам GAE, доступ к которым в настоящее время возможен только из JavaScript, как описано здесь:
https://cloud.google.com/appengine/docs/java/channel/ https://cloud.google.com/appengine/docs/java/channel/javascript
По сути, есть 2 возможных подхода:
- Напишите классы Java, которые «симулируют» доступ, как это сделано здесь: https://github.com/gvsumasl/jacc а>
- Используйте скрытый WebView и подключите JavaScript к Java, как описано здесь: http://developer.android.com/guide/webapps/webview.html
Я пробовал вариант 1, и он работал (поэтому я предполагаю, что код моего сервера в порядке), но я отклонил его, потому что нет гарантии, что Google не изменит свой недокументированный API в будущем.
Я пошел дальше и реализовал следующий код:
Класс Java, который создал WebView и использует события JavaScript:
public class ChannelService {
class ChannelListener {
@JavascriptInterface public void onOpen() {
System.out.println("open"); // PROBLEM: these lines are never called
}
@JavascriptInterface public void onMessage(String message) {
System.out.println("message");
}
@JavascriptInterface public void onError(Integer errorCode, String description) {
System.out.println("error");
}
@JavascriptInterface public void onClose() {
System.out.println("close");
}
}
public ChannelService(Context context) throws IOException {
final WebView webView = new WebView(context);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new ChannelListener(), "channelListener"); // the connection between Java and JavaScript
webView.setWebViewClient(new WebViewClient() {
@Override public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url); // this line is called after the page loads
}
@Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
});
String html = AssetsHelper.assetToString(context, "channels.html"); // loads the html file below
html = html.replaceAll("\\{\\{ channelurl \\}\\}", ApiService.channelUrl()); // channelurl and token are replaced fine and should be correct
html = html.replaceAll("\\{\\{ token \\}\\}", Session.getToken().getId());
webView.loadData(html, "text/html", null);
}
}
Файл channels.html с кодом JavaScript:
<html>
<head>
<script src='{{ channelurl }}jsapi'></script>
</head>
<body>
<script type='text/javascript'>
onOpen = function() {
channelListener.onOpen();
}
onMessage = function(message) {
channelListener.onMessage(message);
}
onError = function(errorcode, description) {
channelListener.onError(errorcode, description);
}
onClose = function() {
channelListener.onClose();
}
openChannel = function() {
var token = '{{ token }}';
var channel = new goog.appengine.Channel(token);
var handler = {
'onopen': onOpen,
'onmessage': onMessage,
'onerror': onError,
'onclose': onClose
};
var socket = channel.open(handler);
socket.onopen = onOpen;
socket.onmessage = onMessage;
socket.onerror = onError;
socket.onclose = onClose;
}
</script>
</body>
</html>
Благодаря Google, WebView не сообщает об ошибках в моем коде, что очень затрудняет отладку. Благодаря себе, я никогда активно не писал код JavaScript, так что здесь я довольно глуп, и вы можете посмеяться и сразу заметить мою ошибку.
Я уже задокументировал это в коде, но позвольте мне указать в другой раз, что работает, а что нет:
- На 95% уверен, что код на стороне сервера работает, так как у меня работал вариант 1. Так что я почти уверен, что мои сообщения отправляются клиенту.
- Я предварительно создаю каналы, когда клиент входит в систему, и передаю токен клиенту через конечные точки REST. Он попадает туда целым (сравнивал), и после replaceAll встраивается тоже нормально.
- Кажется, мой веб-сайт загружается, когда я получаю onPageFinished() с правильным URL-адресом. (ИСПРАВЛЕНО: на самом деле я получаю это событие несколько раз с чем-то, похожим на параметры, но я думаю, что это Android и нормально.)
- Тогда ничего не происходит, никаких исключений, и события Java не вызываются.
- Мой код Java продолжается, и когда я устанавливаю точку останова, WebView может быть получен и жив. Я использовал для него общедоступную переменную в своей деятельности, что должно быть хорошо; и я убедился, что это в потоке пользовательского интерфейса.
Любые идеи приветствуются, либо что я сделал неправильно, либо как я могу отладить это. Спасибо!