henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame^] | 1 | <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> |