blob: a55b8f48bc3398874b77eab60a3e9eb6777bf7c5 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001<html>
2 <head>
3 <script src="http://apprtc.appspot.com/_ah/channel/jsapi"></script>
4 </head>
5 <!--
6 Helper HTML that redirects Google AppEngine's Channel API to Objective C.
7 This is done by hosting this page in an iOS application. The hosting
8 class creates a UIWebView control and implements the UIWebViewDelegate
9 protocol. Then when there is a channel message, it is encoded in an IFRAME.
10 That IFRAME is added to the DOM which triggers a navigation event
11 |shouldStartLoadWithRequest| in Objective C which can then be routed in the
12 application as desired.
13 -->
14 <body onbeforeunload="closeSocket()" onload="openSocket()">
15 <script type="text/javascript">
16 // QueryString is copy/pasta from
17 // chromium's chrome/test/data/media/html/utils.js.
18 var QueryString = function () {
19 // Allows access to query parameters on the URL; e.g., given a URL like:
20 // http://<url>/my.html?test=123&bob=123
21 // parameters can now be accessed via QueryString.test or
22 // QueryString.bob.
23 var params = {};
24
25 // RegEx to split out values by &.
26 var r = /([^&=]+)=?([^&]*)/g;
27
28 // Lambda function for decoding extracted match values. Replaces '+'
29 // with space so decodeURIComponent functions properly.
30 function d(s) { return decodeURIComponent(s.replace(/\+/g, ' ')); }
31
32 var match;
33 while (match = r.exec(window.location.search.substring(1)))
34 params[d(match[1])] = d(match[2]);
35
36 return params;
37 } ();
38
39 var channel = null;
40 var socket = null;
41
42 function openSocket() {
43 if (!QueryString.token || !QueryString.token.match(/^[A-z0-9_-]+$/)) {
44 // Send error back to ObjC. This will assert in GAEChannelClient.m.
45 sendMessageToObjC("JSError:Missing/malformed token parameter " +
46 QueryString.token);
47 throw "Missing/malformed token parameter: " + QueryString.token;
48 }
49 channel = new goog.appengine.Channel(QueryString.token);
50 socket = channel.open({
51 'onopen': function() {
52 sendMessageToObjC("onopen");
53 },
54 'onmessage': function(msg) {
55 sendMessageToObjC("onmessage:" +
56 encodeURIComponent(JSON.stringify(msg.data)));
57 },
58 'onclose': function() {
59 sendMessageToObjC("onclose");
60 },
61 'onerror': function(err) {
62 sendMessageToObjC("onerror:" +
63 encodeURIComponent(JSON.stringify(err.code)) +
64 ":message:" +
65 encodeURIComponent(JSON.stringify(err.description)));
66 }
67 });
68 }
69
70 function closeSocket() {
71 socket.close();
72 }
73
74 // Add an IFRAME to the DOM to trigger a navigation event. Then remove
75 // it as it is no longer needed. Only one event is generated.
76 function sendMessageToObjC(message) {
77 var iframe = document.createElement("IFRAME");
78 iframe.setAttribute("src", "js-frame:" + message);
79 // For some reason we need to set a non-empty size for the iOS6
80 // simulator...
81 iframe.setAttribute("height", "1px");
82 iframe.setAttribute("width", "1px");
83 document.documentElement.appendChild(iframe);
84 iframe.parentNode.removeChild(iframe);
85 }
86 </script>
87 </body>
88</html>