project_files/HedgewarsMobile/Classes/Appirater.m
changeset 4504 8906b2409d97
child 5483 fc755bb8096d
equal deleted inserted replaced
4503:a8ab151bcae3 4504:8906b2409d97
       
     1 /*
       
     2  This file is part of Appirater.
       
     3  
       
     4  Copyright (c) 2010, Arash Payan
       
     5  All rights reserved.
       
     6  
       
     7  Permission is hereby granted, free of charge, to any person
       
     8  obtaining a copy of this software and associated documentation
       
     9  files (the "Software"), to deal in the Software without
       
    10  restriction, including without limitation the rights to use,
       
    11  copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    12  copies of the Software, and to permit persons to whom the
       
    13  Software is furnished to do so, subject to the following
       
    14  conditions:
       
    15  
       
    16  The above copyright notice and this permission notice shall be
       
    17  included in all copies or substantial portions of the Software.
       
    18  
       
    19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    20  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
       
    21  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
       
    22  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       
    23  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       
    24  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
       
    25  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
       
    26  OTHER DEALINGS IN THE SOFTWARE.
       
    27  */
       
    28 /*
       
    29  * Appirater.m
       
    30  * appirater
       
    31  *
       
    32  * Created by Arash Payan on 9/5/09.
       
    33  * http://arashpayan.com
       
    34  * Copyright 2010 Arash Payan. All rights reserved.
       
    35  */
       
    36 
       
    37 #import "Appirater.h"
       
    38 #import <SystemConfiguration/SCNetworkReachability.h>
       
    39 #import <netinet/in.h>
       
    40 
       
    41 NSString *const kAppiraterLaunchDate            = @"kAppiraterLaunchDate";
       
    42 NSString *const kAppiraterLaunchCount           = @"kAppiraterLaunchCount";
       
    43 NSString *const kAppiraterCurrentVersion        = @"kAppiraterCurrentVersion";
       
    44 NSString *const kAppiraterRatedCurrentVersion   = @"kAppiraterRatedCurrentVersion";
       
    45 NSString *const kAppiraterDeclinedToRate        = @"kAppiraterDeclinedToRate";
       
    46 
       
    47 NSString *templateReviewURL = @"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=APP_ID&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software";
       
    48 
       
    49 @interface Appirater (hidden)
       
    50 
       
    51 -(BOOL) connectedToNetwork;
       
    52 
       
    53 @end
       
    54 
       
    55 @implementation Appirater (hidden)
       
    56 
       
    57 -(BOOL) connectedToNetwork {
       
    58     // Create zero addy
       
    59     struct sockaddr_in zeroAddress;
       
    60     bzero(&zeroAddress, sizeof(zeroAddress));
       
    61     zeroAddress.sin_len = sizeof(zeroAddress);
       
    62     zeroAddress.sin_family = AF_INET;
       
    63     
       
    64     // Recover reachability flags
       
    65     SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
       
    66     SCNetworkReachabilityFlags flags;
       
    67     
       
    68     BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
       
    69     CFRelease(defaultRouteReachability);
       
    70     
       
    71     if (!didRetrieveFlags) {
       
    72         NSLog(@"Error. Could not recover network reachability flags");
       
    73         return NO;
       
    74     }
       
    75     
       
    76     BOOL isReachable = flags & kSCNetworkFlagsReachable;
       
    77     BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
       
    78     BOOL nonWiFi = flags & kSCNetworkReachabilityFlagsTransientConnection;
       
    79     
       
    80     NSURL *testURL = [NSURL URLWithString:@"http://www.apple.com/"];
       
    81     NSURLRequest *testRequest = [NSURLRequest requestWithURL:testURL  cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0];
       
    82     NSURLConnection *testConnection = [[NSURLConnection alloc] initWithRequest:testRequest delegate:self];
       
    83     
       
    84     return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO;
       
    85 }
       
    86 
       
    87 @end
       
    88 
       
    89 
       
    90 @implementation Appirater
       
    91 
       
    92 +(void) appLaunched {
       
    93     Appirater *appirater = [[Appirater alloc] init];
       
    94     [NSThread detachNewThreadSelector:@selector(appLaunchedHandler) toTarget:appirater withObject:nil];
       
    95 }
       
    96 
       
    97 -(void) appLaunchedHandler {
       
    98     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
       
    99 
       
   100     if (APPIRATER_DEBUG) {
       
   101         [self performSelectorOnMainThread:@selector(showPrompt) withObject:nil waitUntilDone:NO];
       
   102         return;
       
   103     }
       
   104 
       
   105     BOOL willShowPrompt = NO;
       
   106 
       
   107     // get the app's version
       
   108     NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey];
       
   109 
       
   110     // get the version number that we've been tracking
       
   111     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
       
   112     NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion];
       
   113     if (trackingVersion == nil) {
       
   114         trackingVersion = version;
       
   115         [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
       
   116     }
       
   117     
       
   118     if (APPIRATER_DEBUG)
       
   119         DLog(@"APPIRATER Tracking version: %@", trackingVersion);
       
   120 
       
   121     if ([trackingVersion isEqualToString:version]) {
       
   122         // get the launch date
       
   123         NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterLaunchDate];
       
   124         if (timeInterval == 0) {
       
   125             timeInterval = [[NSDate date] timeIntervalSince1970];
       
   126             [userDefaults setDouble:timeInterval forKey:kAppiraterLaunchDate];
       
   127         }
       
   128 
       
   129         NSTimeInterval secondsSinceLaunch = [[NSDate date] timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:timeInterval]];
       
   130         double secondsUntilPrompt = 60 * 60 * 24 * DAYS_UNTIL_PROMPT;
       
   131 
       
   132         // get the launch count
       
   133         int launchCount = [userDefaults integerForKey:kAppiraterLaunchCount];
       
   134         launchCount++;
       
   135         [userDefaults setInteger:launchCount forKey:kAppiraterLaunchCount];
       
   136         if (APPIRATER_DEBUG)
       
   137             NSLog(@"APPIRATER Launch count: %d", launchCount);
       
   138 
       
   139         // have they previously declined to rate this version of the app?
       
   140         BOOL declinedToRate = [userDefaults boolForKey:kAppiraterDeclinedToRate];
       
   141 
       
   142         // have they already rated the app?
       
   143         BOOL ratedApp = [userDefaults boolForKey:kAppiraterRatedCurrentVersion];
       
   144 
       
   145         if (secondsSinceLaunch > secondsUntilPrompt &&
       
   146              launchCount > LAUNCHES_UNTIL_PROMPT &&
       
   147              !declinedToRate &&
       
   148              !ratedApp) {
       
   149             if ([self connectedToNetwork]) {	// check if they can reach the app store
       
   150                 willShowPrompt = YES;
       
   151                 [self performSelectorOnMainThread:@selector(showPrompt) withObject:nil waitUntilDone:NO];
       
   152             }
       
   153         }
       
   154     } else {
       
   155         // it's a new version of the app, so restart tracking
       
   156         [userDefaults setObject:version forKey:kAppiraterCurrentVersion];
       
   157         [userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterLaunchDate];
       
   158         [userDefaults setInteger:1 forKey:kAppiraterLaunchCount];
       
   159         [userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion];
       
   160         [userDefaults setBool:NO forKey:kAppiraterDeclinedToRate];
       
   161     }
       
   162 
       
   163     [userDefaults synchronize];
       
   164     if (!willShowPrompt)
       
   165         [self autorelease];
       
   166 
       
   167     [pool release];
       
   168 }
       
   169 
       
   170 -(void) showPrompt {
       
   171     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:APPIRATER_MESSAGE_TITLE
       
   172                                                         message:APPIRATER_MESSAGE
       
   173                                                        delegate:self
       
   174                                               cancelButtonTitle:APPIRATER_CANCEL_BUTTON
       
   175                                               otherButtonTitles:APPIRATER_RATE_BUTTON, APPIRATER_RATE_LATER, nil];
       
   176     [alertView show];
       
   177     [alertView release];
       
   178 }
       
   179 
       
   180 -(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger) buttonIndex {
       
   181     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
       
   182 
       
   183     switch (buttonIndex) {
       
   184         case 0:
       
   185             // they don't want to rate it
       
   186             [userDefaults setBool:YES forKey:kAppiraterDeclinedToRate];
       
   187             break;
       
   188         case 1:
       
   189             // they want to rate it
       
   190             [[UIApplication sharedApplication] openURL:
       
   191              [NSURL URLWithString:[templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%d", APPIRATER_APP_ID]]]];
       
   192             
       
   193             [userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion];
       
   194             break;
       
   195         case 2:
       
   196             // remind them later
       
   197             break;
       
   198         default:
       
   199             break;
       
   200     }
       
   201 
       
   202     [userDefaults synchronize];
       
   203 
       
   204     [self release];
       
   205 }
       
   206 
       
   207 @end