技術と趣味の亜空間

主にゲームプログラミングとその周辺に関する記事を不定期で上げていきます

ネイティブアプリのAPI更新対応備忘録 〜iOS編〜

Apple Logo

概要

qiita.com

↑を対応しつつ、その他 deprecated なコードの修正対応をメモがてら記載していく。
なお、修正前の時点で Project の iOS Deployment Target は iOS8 だった。
今回はそれを iOS11 まで引き上げることとする。というのも、WKWebView自体は iOS8からサポートされているが、 iOS10までと11以降でほぼ別物のため、保守管理の観点からiOS11以降に限定させた。
対応時のXcodeバージョン: 11.5

また、この記事は公開後も更新があった場合は追記する予定です。

UIWebView → WKWebView

UIWebView をプロジェクト内から完全に駆逐する。
ターミナルでプロジェクトへ移動し、以下を入力して使われている箇所を把握する

grep -r "UIWebView" .

そして上記の箇所をすべて WKWebView に変えていく。
また、Storyboard の View で使われている Web View (deprecated) コンポーネントWebKit View に変更。
Twitter 連携用のコードでも UIWebView が使われていたので WKWebView に変更。
またFacebookSDKが古すぎてそちらでもUIWebViewが使われていたので最新のSDKにバージョンアップさせた。具体的な最新作業については 「FacebookSDKの更新」欄を参照。

参考サイト:

通信周り

NSURLConnection で同期通信をしていたが、 このクラスは iOS9 で deprecated になり、 NSURLSession へ修正。
NSURLSession は非同期しか対応しておらず、今からガッツリ変えるのはリスキーなのでディスパッチセマフォで同期処理にする。

Before

-(BOOL)sendSynchronousRequest:(NSString *)ua {
    NSString* version =  [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@?p=%@", ROOT_URL, ENVIRONMENT_URL, version]];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:ua forHTTPHeaderField:@"User-Agent"];
    NSURLResponse *response = nil;
    NSError *error = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    NSString *errorStr = [error localizedDescription];
    if ([errorStr length] > 0) {
        DLOG(@"error message: %@", errorStr);
    }

    return [self decrypt:data];
}

After

-(BOOL)sendSynchronousRequest:(NSString *)ua {
    NSString* version =  [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@?p=%@", ROOT_URL, ENVIRONMENT_URL, version]];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:ua forHTTPHeaderField:@"User-Agent"];

    // 同期通信
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    __block BOOL isSuccess = YES;
    __block NSData *resData = nil;
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:(NSURLRequest *)request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error){
        // error
        NSString *errorStr = [error localizedDescription];
        if ([errorStr length] > 0) {
            DLOG(@"error message: %@", errorStr);
            isSuccess = NO;
            dispatch_semaphore_signal(semaphore);
            return;
        }

        resData = data;
        dispatch_semaphore_signal(semaphore);
    }];
    [task resume];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    if(!isSuccess) {
        return NO;
    }
    
    return [self decrypt:resData];
}

デリゲート利用クラス

また、NSURLConnectionのデリゲートを利用していたクラスはNSURLSessionのデリゲートへ変更する。

/**
 * HTTPリクエスト
 */
- (void)post:(PostData * )postData_ {
    // 初期化
    webData = [NSMutableData data];
    // セッション作成
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    
    // 通信設定
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                          delegate:self
                                                     delegateQueue:[NSOperationQueue mainQueue]];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:theRequest];
    
    // 通信開始
    [task resume];
}

/**
 * HTTPリクエストのデリゲートメソッド(データ受け取り初期処理)
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                 didReceiveResponse:(NSURLResponse *)response
                                  completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    
    if (httpResponse.statusCode == 200) {
        // 保持していたレスポンスのデータを初期化
        [webData setLength: 0];
        // didReceivedData と didCompleteWithError が呼ばれるように、通常継続の定数をハンドラーに渡す
        completionHandler(NSURLSessionResponseAllow);   // 続ける
    } else {
        // error.code = -999で終了メソッドが呼ばれる
        completionHandler(NSURLSessionResponseCancel);  // 止める
    }
}

/**
 * HTTPリクエストのデリゲートメソッド(受信の度に実行)
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
    // 1つのパケットに収まらないデータ量の場合は複数回呼ばれるので、データを追加していく
    [webData appendData:data];
}

/**
 * HTTPリクエストのデリゲートメソッド(完了処理)  [正常終了、エラー終了、途中終了でもこのメソッドが呼ばれる]
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
       if (error) {
           // エラー終了
       } else {
           // 完了通知
       }
    
    [session invalidateAndCancel];
}

参考サイト:

UIAlertView → UIAlertController

UIAlertView は iOS8 で deprecated になったため、 UIAlertController へ変更。
これにより、アラート表示処理が大きく変わってしまい、表示元の UIViewControllerインスタンスが必要になった。
ViewController をなんとか検索して取得する方法を下記参考サイトを見つつ対応。

Before

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message
                                                   delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];

After

    //コントローラーの生成
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:message preferredStyle:UIAlertControllerStyleAlert];
    //ボタンとその機能を生成
    UIAlertAction *OKAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
    //コントローラーにボタンを追加
    [alert addAction:OKAction];
    //アラートを表示
    [self presentViewController:alert animated:YES completion:nil];

参考サイト:

プッシュ通知

プッシュ通知のコードをUNUserNotificationCenterを利用したものへ変更。 気をつける点としては以下の2点。

  1. 通知のデリゲートを受け取る場合は UNUserNotificationCenterDelegate をヘッダーに宣言し、今まで利用してきた通知デリゲートメソッドはUNUserNotificationCenterDelegate で用意されているやつに差し替える必要がある。
  2. 通知をキャンセルする場合、古いやり方だと cancelAllLocalNotifications を呼ぶだけで全部削除されたが、新しい方法では removeAllPendingNotificationRequestsremoveAllDeliveredNotifications を呼ぶ必要がある。前者は未送信の通知をすべて削除し、後者は送信済みの通知を削除する。

Before

MyAppDelegate.h

@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
}

MyAppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    CGFloat currentVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (currentVersion >= 8.0) {
        // iOS8.0以降の処理
        //UserNotificationの種類(バッヂ、アラート、サウンド)
        UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound;
        // User Notificationの設定を登録
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
        [application registerUserNotificationSettings:settings];
        // Remote Notificationの設定を登録
        [application registerForRemoteNotifications];
    }
    else {
        // iOS7以前の処理
        // Remote Notificationの種類
        UIRemoteNotificationType types = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
        // Remote Notificationの設定を登録
        [application registerForRemoteNotificationTypes:types];
    }

    // アプリを起動したら、ローカル通知設定をクリア
    [application cancelAllLocalNotifications];
}

After

MyAppDelegate.h

@interface MyAppDelegate : NSObject <UIApplicationDelegate, UNUserNotificationCenterDelegate> {
}

MyAppDelegate.m

#import <UserNotifications/UserNotifications.h>

// 略...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // プッシュ通知受信用の処理
    UNUserNotificationCenter *notificationCenter = [UNUserNotificationCenter currentNotificationCenter];
    //UserNotificationの種類
    UNAuthorizationOptions options = UNAuthorizationOptionAlert
    | UNAuthorizationOptionAlert | UNAuthorizationOptionSound;
    // デリゲートを接続
    notificationCenter.delegate = self;
    // User Notificationを登録
    [notificationCenter requestAuthorizationWithOptions:options completionHandler:
     ^(BOOL granted, NSError * _Nullable error) {
        if (error) {
            NSLog(@"requestAuthorizationWithOptions error: %@", error);
            return;
        }
        if (granted) {
            // ユーザが Push 通知を許可するとここに来る
            dispatch_async(dispatch_get_main_queue(), ^ {
                [[UIApplication sharedApplication] registerForRemoteNotifications];
            });
        }
    }];

    // アプリを起動したら、ローカル通知設定をクリア
    [notificationCenter removeAllPendingNotificationRequests];
    [notificationCenter removeAllDeliveredNotifications];
}

参考サイト

URLエンコード/デコードAPI

エンコード・デコード周りのコードも古かったので差し替え。
エンコードCFURLCreateStringByAddingPercentEscapes を利用していたので stringByAddingPercentEncodingWithAllowedCharacters に変更。

- (NSString *)stringByEncodingURLFormat {
    return [(NSString *)self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];
}

デコードの方は stringByReplacingPercentEscapesUsingEncoding から stringByRemovingPercentEncodingへ変更。

- (NSString *)stringByDecodingURLFormat {
    return [result stringByRemovingPercentEncoding];
}

参考サイト:
[Objective-C] iOS9からのURLエンコード・デコード | Tips of Rubbish

topLayoutGuide.length

self.topLayoutGuide.length が iOS11 でdeprecated なので view.safeAreaInsets で取得するように変更。

Before

topOffset = self.topLayoutGuide.length;

After

topOffset = self.view.safeAreaInsets.top;

参考サイト:

ステータスバーの表示・非表示API修正

UIApplicationsetstatusbarhidden が iOS9 で deprecated になり、作り方が大きく変わっていた。
最初にInfo.plistの「View controller-based status bar appearance」をYESに変更後、以下のようにステータスバーを隠すコードを修正。
上記の変更により、複数Viewがある場合はそれぞれのクラスで設定が必要なので注意。

Before

// ステータスバーを隠す
- (void)hideStatusBar {
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
    // hogehoge
}

After

// インスタンス変数
bool shouldBeHidingStatusBar = NO;
UIStatusBarAnimation statusBarAnimationType = UIStatusBarAnimationSlide;

// ステータスバーを隠す
- (void)hideStatusBar {
    shouldBeHidingStatusBar = YES;
    statusBarAnimationType = UIStatusBarAnimationSlide;
    [UIView animateWithDuration:0.5 animations:^{
        [self setNeedsStatusBarAppearanceUpdate];
    } completion:^(bool isFinished) {
        // hogehoge
    }];
}

//YESでステータスバーを非表示(NOなら表示)
- (BOOL)prefersStatusBarHidden {
    return shouldBeHidingStatusBar;
}

//スライドするアニメーションを指定
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
    return statusBarAnimationType;
}

//ステータスバーの色を指定
- (UIStatusBarStyle)preferredStatusBarStyle {
    // 白で固定
    return UIStatusBarStyleLightContent;
}

上記のように、 prefersStatusBarXXX 系のメソッドは
UIViewControllerののAPIとして予め用意されているものであり、これらのメソッドを宣言して返り値に適切な変数を返してやる必要がある。
これらの設定の反映を適用するには setNeedsStatusBarAppearanceUpdate メソッドを呼ぶ必要がある。

参考サイト:
iOSのステータスバーを自在に扱う - Qiita

ステータスバーのサイズを除いた全画面サイズ取得API

UIScreen:applicationFrame の差し替え対応。

Before

size = [[UIScreen mainScreen] applicationFrame].size;

After

 // 全画面サイズ
size = [[UIScreen mainScreen] bounds].size;
// ステータスバー分のサイズを除く
size.height = size.height - UIApplication.sharedApplication.statusBarFrame.size.height;
size.width = size.width - UIApplication.sharedApplication.statusBarFrame.size.width; 

参考サイト:

カメラ周り

写真データ取得に使っていた AVCaptureStillImageOutput が iOS9 で deprecated になったので AVCapturePhotoOutput に修正。

CaptureSessionManager.h

Before

@interface CaptureSessionManager : NSObject<CaptureSessionManagerDelegate> { }

@property (nonatomic, retain) AVCaptureStillImageOutput *stillImageOutput;

After

@interface CaptureSessionManager : NSObject<CaptureSessionManagerDelegate, AVCapturePhotoCaptureDelegate> { }

@property (nonatomic, retain) AVCapturePhotoOutput *stillImageOutput;

CaptureSessionManager.m

Before

- (void)addVideoOutput{
    stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [stillImageOutput setOutputSettings:outputSettings];
}

// 撮影
- (void)capture{

   // 略

    [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

        CFDictionaryRef exifAttachments = CMGetAttachment( imageDataSampleBuffer, kCGImagePropertyExifDictionary, NULL);

        if (imageDataSampleBuffer == NULL) return;
        
        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        UIImage *image = [[UIImage alloc] initWithData:imageData];

        // hogehoge
    }];
}

After

- (void)addVideoOutput{
    stillImageOutput = [[AVCapturePhotoOutput alloc] init];
    [captureSession addOutput:stillImageOutput];
}

// 撮影
- (void)capture{
    AVCapturePhotoOutput * output = (AVCapturePhotoOutput *)stillImageOutput;

    videoConnection = [output connectionWithMediaType:AVMediaTypeVideo];
    AVCapturePhotoSettings * settings = [AVCapturePhotoSettings photoSettings];

    [output capturePhotoWithSettings:settings delegate:self];
}

// 撮影時のコールバック
- (void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo error:(nullable NSError *)error
{
    NSData *imageData = [photo fileDataRepresentation];
    UIImage* resutImage = [[UIImage alloc] initWithData:imageData];

    // hogehoge
}

参考サイト:

Custom URL scheme起動用のメソッド

iOS9 以下で使っていた、

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation

はdeprecatedになったので、以下のメソッドで対応する。

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options

参考サイト:
公式ドキュメント

sizeWithFont:constrainedToSize

iOS7 で deprecatedになった sizeWithFont:constrainedToSize を変更。

Before

CGSize dims = [self.labelText sizeWithFont:self.labelFont];
// 中略
CGFloat maxHeight = frame.size.height - self.height - 2*margin;
CGSize labelSize = [detailsLabel.text sizeWithFont:detailsLabel.font constrainedToSize:CGSizeMake(frame.size.width - 4*margin, maxHeight) lineBreakMode:detailsLabel.lineBreakMode];
lHeight = labelSize.height;
lWidth = labelSize.width;

After

NSDictionary *labelDatas = @{NSFontAttributeName: self.labelFont};
CGSize dims = [self.labelText sizeWithAttributes:labelDatas];
// 中略
CGFloat maxHeight = frame.size.height - self.height - 2*margin;
NSDictionary *detailsLabelData = @{NSFontAttributeName: detailsLabel};
CGRect labelSize = [detailsLabel.text boundingRectWithSize:CGSizeMake(frame.size.width - 4*margin, maxHeight) options:NSStringDrawingUsesLineFragmentOrigin attributes:detailsLabelData context:nil];
lHeight = labelSize.size.height;
lWidth = labelSize.size.width;

参考サイト: 非推奨になった sizeWithFont:constrainedToSize:lineBreakMode を置き換える - Qiita

openURL

UIApplicationopenURL を更新する。

Brefore

[[UIApplication sharedApplication] openURL:url];

After

[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];

参考サイト: [iOS 10] UIApplication の openURL: が Deprecated になりました | Developers.IO

課金レシート情報

課金した時のレシートを受け取るAPItransactionReceiptだったので変更する。
レシート情報の構造が変わるのでサーバー側のレシート検証周りのコードも合わせて修正する必要有り。

Before

NSString * data = [transaction.transactionReceipt base64EncodingWithLineLength:0];
// サーバーへ送る

After

NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
if (!receiptData) { 
    NSLog(@"no receipt");
    // エラーハンドリング
} else {
    NSString *data = [receiptData base64EncodedStringWithOptions:0];
    // サーバーへ送る
}

レシートのレスポンス

どこよりもわかりやすいiOS最強課金まとめ - Qiita より引用しました。

{
    "status": 0,
    "environment": "Sandbox",
    "receipt": {
        "receipt_type": "ProductionSandbox",
        "adam_id": 0,
        "app_item_id": 0,
        "bundle_id": " ",
        "application_version": "1",
        "download_id": 0,
        "version_external_identifier": 0,
        "receipt_creation_date": "2019-11-12 08:55:19 Etc/GMT",
        "receipt_creation_date_ms": "1573548919000",
        "receipt_creation_date_pst": "2019-11-12 00:55:19 America/Los_Angeles",
        "request_date": "2019-11-18 12:58:25 Etc/GMT",
        "request_date_ms": "1574081905053",
        "request_date_pst": "2019-11-18 04:58:25 America/Los_Angeles",
        "original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
        "original_purchase_date_ms": "1375340400000",
        "original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
        "original_application_version": "1.0",
        "in_app": [
            {
                "quantity": "1",
                "product_id": " ",
                "transaction_id": "1000000590999315",
                "original_transaction_id": "1000000590999315",
                "purchase_date": "2019-11-12 08:55:18 Etc/GMT",
                "purchase_date_ms": "1573548918000",
                "purchase_date_pst": "2019-11-12 00:55:18 America/Los_Angeles",
                "original_purchase_date": "2019-11-12 08:55:19 Etc/GMT",
                "original_purchase_date_ms": "1573548919000",
                "original_purchase_date_pst": "2019-11-12 00:55:19 America/Los_Angeles",
                "expires_date": "2019-11-12 08:58:18 Etc/GMT",
                "expires_date_ms": "1573549098000",
                "expires_date_pst": "2019-11-12 00:58:18 America/Los_Angeles",
                "web_order_line_item_id": "1000000048178827",
                "is_trial_period": "false",
                "is_in_intro_offer_period": "false"
            }
        ]
    },
    "latest_receipt_info": [
        {
            "quantity": "1",
            "product_id": " ",
            "transaction_id": "1000000590999315",
            "original_transaction_id": "1000000590999315",
            "purchase_date": "2019-11-12 08:55:18 Etc/GMT",
            "purchase_date_ms": "1573548918000",
            "purchase_date_pst": "2019-11-12 00:55:18 America/Los_Angeles",
            "original_purchase_date": "2019-11-12 08:55:19 Etc/GMT",
            "original_purchase_date_ms": "1573548919000",
            "original_purchase_date_pst": "2019-11-12 00:55:19 America/Los_Angeles",
            "expires_date": "2019-11-12 08:58:18 Etc/GMT",
            "expires_date_ms": "1573549098000",
            "expires_date_pst": "2019-11-12 00:58:18 America/Los_Angeles",
            "web_order_line_item_id": "1000000048178827",
            "is_trial_period": "false",
            "is_in_intro_offer_period": "false",
            "subscription_group_identifier": "20567235"
        }
    ],
    "latest_receipt": " ",
    "pending_renewal_info": [
        {
            "expiration_intent": "1",
            "auto_renew_product_id": " ",
            "original_transaction_id": "1000000590999315",
            "is_in_billing_retry_period": "0",
            "product_id": " ",
            "auto_renew_status": "0"
        }
    ]
}

参考サイト:

MobileCoreServices.framework → CoreServices.framework

タイトル通り。

OpenGLES.framework → Metal.framework

タイトル通り。

FacebookSDKの更新

FacebookSDKのバージョンが v.3 系と相当古かったので更新。
執筆時点での最新版であるv.7にアップグレードさせた。
更新方法は公式ドキュメントを参考にしつつ、Swift Packagesでダウンロードする方式に差し替えた。
また、今回は元々Obj-cなプロジェクトのため、Swiftライブラリが利用できるように Project の Build Settings で以下の設定を行った。

  1. Build Option -> Always Embed Swift Standartd LibrariesYES に変更
  2. Linking -> Runpath Search Paths@executable_path/Frameworks を追加
  3. 念の為 Product -> Clean Build で過去のビルドキャッシュを削除

上記を設定しないと、ビルドは成功するが端末だと起動直後、
dyld: Library not loaded: @rpath/libswiftCore.dylib
というエラーで動かないので注意が必要。

参考サイト:

ローカルライブラリのパス整理

ビルド時に発生する、

ld: warning: directory not found for option

の解消対応。
1. Build Settings -> Search Paths -> Always Search User Paths (Deprecated)NO に変更

参考サイト:
xcode - ‘ld: warning: directory not found for option’ - Stack Overflow

モーダル表示方法の修正

iOS13以降ではモーダル表示方法の設定が特に記載されていない場合、カード型の UIで表示されるようになりました。
自分のプロジェクトではこれまで通りフルスクリーンで表示させたいため、以下のように設定。

vc.modalPresentationStyle =  UIModalPresentationFullScreen;  //表示形式の選択
vc.modalInPopover = YES;  //YESにするとスワイプで消えなくなる
// モーダル表示
[self presentViewController:vc animated:YES completion:nil];

参考サイト:
iOS 13 以降でモーダルを fullScreen 表示させる3つの方法 - Qiita

感想

iOS8 から 11 に変えるだけでも結構な変更がありますね。
最近発表されたiOS14ではホーム画面のUIに大きなテコ入れがあり、また広告周りのセキュリティが厳しくなるのでAdjustとか使っている方は更新する必要があるかもです。

ページトップのロゴは、Apple Inc.の商標です。