61e78fca6c
Previously GAE Channel callbacks would be handled by JS string-encoding the payload into a URL. Unfortunately this is limited to the (undocumented, silently problematic) maximum URL length UIWebView supports. Replaced this scheme by a notification from JS to ObjC and a getter from ObjC to JS (which happens out-of-line to avoid worrying about UIWebView's re-entrancy, or lack thereof). Part of this change also moved from a combination of: JSON, URL-escaping, and ad-hoc :-separated values to simply JSON. Also incidentally: - Removed outdated TODO about onRenegotiationNeeded, which is unneeded - Move handling of PeerConnection callbacks to the main queue to avoid having to think about concurrency too hard. - Replaced a bunch of NSOrderedSame with isEqualToString for clearer code and not having to worry about the fact that [nil compare:@"foo"]==NSOrderedSame is always true (yay ObjC!). - Auto-scroll messages view. BUG=3117 R=noahric@google.com Review URL: https://webrtc-codereview.appspot.com/10899006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5814 4adac7df-926f-26a2-2b94-8c16560cd09d
95 lines
3.5 KiB
HTML
95 lines
3.5 KiB
HTML
<html>
|
|
<head>
|
|
<script src="http://apprtc.appspot.com/_ah/channel/jsapi"></script>
|
|
</head>
|
|
<!--
|
|
Helper HTML that redirects Google AppEngine's Channel API to Objective C.
|
|
This is done by hosting this page in an iOS application. The hosting
|
|
class creates a UIWebView control and implements the UIWebViewDelegate
|
|
protocol. Then when there is a channel message it is queued in JS,
|
|
and an IFRAME is added to the DOM, triggering a navigation event
|
|
|shouldStartLoadWithRequest| in Objective C which can then fetch the
|
|
message using |popQueuedMessage|. This queuing is necessary to avoid URL
|
|
length limits in UIWebView (which are undocumented).
|
|
-->
|
|
<body onbeforeunload="closeSocket()" onload="openSocket()">
|
|
<script type="text/javascript">
|
|
// QueryString is copy/pasta from
|
|
// chromium's chrome/test/data/media/html/utils.js.
|
|
var QueryString = function () {
|
|
// Allows access to query parameters on the URL; e.g., given a URL like:
|
|
// http://<url>/my.html?test=123&bob=123
|
|
// parameters can now be accessed via QueryString.test or
|
|
// QueryString.bob.
|
|
var params = {};
|
|
|
|
// RegEx to split out values by &.
|
|
var r = /([^&=]+)=?([^&]*)/g;
|
|
|
|
// Lambda function for decoding extracted match values. Replaces '+'
|
|
// with space so decodeURIComponent functions properly.
|
|
function d(s) { return decodeURIComponent(s.replace(/\+/g, ' ')); }
|
|
|
|
var match;
|
|
while (match = r.exec(window.location.search.substring(1)))
|
|
params[d(match[1])] = d(match[2]);
|
|
|
|
return params;
|
|
} ();
|
|
|
|
var channel = null;
|
|
var socket = null;
|
|
// In-order queue of messages to be delivered to ObjectiveC.
|
|
// Each is a JSON.stringify()'d dictionary containing a 'type'
|
|
// field and optionally a 'payload'.
|
|
var messageQueue = [];
|
|
|
|
function openSocket() {
|
|
if (!QueryString.token || !QueryString.token.match(/^[A-z0-9_-]+$/)) {
|
|
// Send error back to ObjC. This will assert in GAEChannelClient.m.
|
|
sendMessageToObjC("JSError:Missing/malformed token parameter " +
|
|
QueryString.token);
|
|
throw "Missing/malformed token parameter: " + QueryString.token;
|
|
}
|
|
channel = new goog.appengine.Channel(QueryString.token);
|
|
socket = channel.open({
|
|
'onopen': function() {
|
|
sendMessageToObjC("onopen");
|
|
},
|
|
'onmessage': function(msg) {
|
|
sendMessageToObjC("onmessage", msg);
|
|
},
|
|
'onclose': function() {
|
|
sendMessageToObjC("onclose");
|
|
},
|
|
'onerror': function(err) {
|
|
sendMessageToObjC("onerror", err);
|
|
}
|
|
});
|
|
}
|
|
|
|
function closeSocket() {
|
|
socket.close();
|
|
}
|
|
|
|
// Add an IFRAME to the DOM to trigger a navigation event. Then remove
|
|
// it as it is no longer needed. Only one event is generated.
|
|
function sendMessageToObjC(type, payload) {
|
|
messageQueue.push(JSON.stringify({'type': type, 'payload': payload}));
|
|
var iframe = document.createElement("IFRAME");
|
|
iframe.setAttribute("src", "js-frame:");
|
|
// For some reason we need to set a non-empty size for the iOS6
|
|
// simulator...
|
|
iframe.setAttribute("height", "1px");
|
|
iframe.setAttribute("width", "1px");
|
|
document.documentElement.appendChild(iframe);
|
|
iframe.parentNode.removeChild(iframe);
|
|
}
|
|
|
|
function popQueuedMessage() {
|
|
return messageQueue.shift();
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|