Home | History | Annotate | Download | only in AppRTCDemo
      1 /*
      2  * libjingle
      3  * Copyright 2013, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #import "GAEChannelClient.h"
     29 
     30 #import "RTCPeerConnectionFactory.h"
     31 
     32 #if TARGET_OS_IPHONE
     33 
     34 #import <UIKit/UIKit.h>
     35 
     36 @interface GAEChannelClient () <UIWebViewDelegate>
     37 
     38 @property(nonatomic, strong) UIWebView* webView;
     39 
     40 #else
     41 
     42 #import <WebKit/WebKit.h>
     43 
     44 @interface GAEChannelClient ()
     45 
     46 @property(nonatomic, strong) WebView* webView;
     47 
     48 #endif
     49 
     50 @end
     51 
     52 @implementation GAEChannelClient
     53 
     54 - (instancetype)initWithToken:(NSString*)token
     55                      delegate:(id<GAEMessageHandler>)delegate {
     56   NSParameterAssert([token length] > 0);
     57   NSParameterAssert(delegate);
     58   self = [super init];
     59   if (self) {
     60 #if TARGET_OS_IPHONE
     61     _webView = [[UIWebView alloc] init];
     62     _webView.delegate = self;
     63 #else
     64     _webView = [[WebView alloc] init];
     65     _webView.policyDelegate = self;
     66 #endif
     67     _delegate = delegate;
     68     NSString* htmlPath =
     69         [[NSBundle mainBundle] pathForResource:@"channel" ofType:@"html"];
     70     NSURL* htmlUrl = [NSURL fileURLWithPath:htmlPath];
     71     NSString* path = [NSString
     72         stringWithFormat:@"%@?token=%@", [htmlUrl absoluteString], token];
     73 #if TARGET_OS_IPHONE
     74     [_webView
     75 #else
     76     [[_webView mainFrame]
     77 #endif
     78         loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:path]]];
     79   }
     80   return self;
     81 }
     82 
     83 - (void)dealloc {
     84 #if TARGET_OS_IPHONE
     85   _webView.delegate = nil;
     86   [_webView stopLoading];
     87 #else
     88   _webView.policyDelegate = nil;
     89   [[_webView mainFrame] stopLoading];
     90 #endif
     91 }
     92 
     93 #if TARGET_OS_IPHONE
     94 #pragma mark - UIWebViewDelegate
     95 
     96 - (BOOL)webView:(UIWebView*)webView
     97     shouldStartLoadWithRequest:(NSURLRequest*)request
     98                 navigationType:(UIWebViewNavigationType)navigationType {
     99 #else
    100 // WebPolicyDelegate is an informal delegate.
    101 #pragma mark - WebPolicyDelegate
    102 
    103 - (void)webView:(WebView*)webView
    104     decidePolicyForNavigationAction:(NSDictionary*)actionInformation
    105                             request:(NSURLRequest*)request
    106                               frame:(WebFrame*)frame
    107                    decisionListener:(id<WebPolicyDecisionListener>)listener {
    108 #endif
    109   NSString* scheme = [request.URL scheme];
    110   NSAssert(scheme, @"scheme is nil: %@", request);
    111   if (![scheme isEqualToString:@"js-frame"]) {
    112 #if TARGET_OS_IPHONE
    113     return YES;
    114 #else
    115     [listener use];
    116     return;
    117 #endif
    118   }
    119   dispatch_async(dispatch_get_main_queue(), ^{
    120       NSString* queuedMessage = [webView
    121           stringByEvaluatingJavaScriptFromString:@"popQueuedMessage();"];
    122       NSAssert([queuedMessage length], @"Empty queued message from JS");
    123 
    124       NSDictionary* queuedMessageDict =
    125           [GAEChannelClient jsonStringToDictionary:queuedMessage];
    126       NSString* method = queuedMessageDict[@"type"];
    127       NSAssert(method, @"Missing method: %@", queuedMessageDict);
    128       NSDictionary* payload = queuedMessageDict[@"payload"];  // May be nil.
    129 
    130       if ([method isEqualToString:@"onopen"]) {
    131         [self.delegate onOpen];
    132       } else if ([method isEqualToString:@"onmessage"]) {
    133         NSDictionary* payloadData =
    134             [GAEChannelClient jsonStringToDictionary:payload[@"data"]];
    135         [self.delegate onMessage:payloadData];
    136       } else if ([method isEqualToString:@"onclose"]) {
    137         [self.delegate onClose];
    138       } else if ([method isEqualToString:@"onerror"]) {
    139         NSNumber* codeNumber = payload[@"code"];
    140         int code = [codeNumber intValue];
    141         NSAssert([codeNumber isEqualToNumber:[NSNumber numberWithInt:code]],
    142                  @"Unexpected non-integral code: %@", payload);
    143         [self.delegate onError:code withDescription:payload[@"description"]];
    144       } else {
    145         NSAssert(NO, @"Invalid message sent from UIWebView: %@", queuedMessage);
    146       }
    147   });
    148 #if TARGET_OS_IPHONE
    149   return NO;
    150 #else
    151   [listener ignore];
    152   return;
    153 #endif
    154 }
    155 
    156 #pragma mark - Private
    157 
    158 + (NSDictionary*)jsonStringToDictionary:(NSString*)str {
    159   NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];
    160   NSError* error;
    161   NSDictionary* dict =
    162       [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
    163   NSAssert(!error, @"Invalid JSON? %@", str);
    164   return dict;
    165 }
    166 
    167 @end
    168