LoginSignup
12
11

More than 5 years have passed since last update.

個人用アカウントでAppGroupを用いたチーム開発を行なう

Last updated at Posted at 2015-05-26

問題点

iOS8でアプリ間でデータを共有する仕組みとしてAppGroupが導入された。カスタムキーボードやAppleWatchアプリ等の拡張は別アプリとなるため、これらを開発をする際はAppGroupの利用が事実上必須である。 (参考: http://www.toyship.org/archives/1845)

AppGroupは開発者アカウントごとのデータであり、かつ、世界中で一意となる名前を持たねばならない。 個人(Individual)アカウントは複数人で共有できないため、同じAppGroupを使うことができない。企業(Company/Organization)アカウントならばAppGroupの共有が可能だが、取得には法人である必要がある。

そのため、法人でない団体(例: 大学サークル等)では、AppGroupの利用が難しい。

解決策

以下の方針で、開発を複数人で行なえるようにする。

  • 開発者ごとにAppGroup名/Bundle Identifierを変更する。
  • AppGroup名/Bundle Identifierを具体的に書く箇所を一箇所にすることで、容易に変更できるようにする。

ただし、AppStoreに提出できるのは誰か一人という制約は解決できないため、誰かが正式版のビルド係/AppStoreへの提出係となる必要がある。

手順

Xcode 6.3.2をもとに手順を記述する。

Config.xcconfigを作成する

以下の内容の Config.xcconfig を作成し、プロジェクトに追加する。

// 以下の行を開発者ごとに変更すること
APP_IDENTIFIER = org.example.mzp.some_app

GCC_PREPROCESSOR_DEFINITIONS = $(inherited) APP_IDENTIFIER=${APP_IDENTIFIER}

gitで管理している場合は以下のようにするとよい。

  • 上記の内容をConfig.xcconfig.exampleに記述する
  • .gitignoreでConfig.xcconfigを無視するようにするように設定する
  • 開発者がcloneした直後にConfig.xcconfigをConfig.xcconfig.examlpeを元に作成するようにするようREADME等に記述する

Config.xcconfigを追加する

プロジェクト -> Info -> Configurationsで Config.xcconfig を使うように設定する。

config.png

Info.plistの変更

各ターゲットの Info.plist 内のBundle identifierを用いている部分を $(APP_IDENTIFIER) で置換する。
ターゲットの種類によって置き換えなければならない箇所は異なる。

info.png

AppGroupの有効化

各ターゲットのCapabilitiesからAppGroupを有効にする。
また、下の「+」ボタンで、AppGroupの作成も行なえる。

export.png

*.entitlementsの変更

<アプリ名>.entilements が追加されるので、AppGroup名をgroup.$(APP_IDENTIFIER) で置換する。

entitlements.png

ラッパクラスの作成

アプリ内でAppGroupを用いた処理をできるようラッパクラスを作成する。CPPマクロを利用するため、Objective-Cでなければならない。

Objectvie-Cのため、Swiftから利用する場合はBridge Headerを適切に設定する必要がある。

AppGroup.h

#import <Foundation/Foundation.h>

// AppGroupに関係する情報のラッパ。
//
// 個人アカウントを使っているため、ユーザに応じてAppGroup名を変える必要がある。
// AppGroup名はConfig.xcconfig内でCPPマクロとして定義されているため、Swiftからは読むことができない。
// そのためObjective-Cで記述する。
@interface AppGroup : NSObject

// AppGroup名
+ (NSString *)appGroupID;

// AppGroupで共有された領域のパスを取得
+ (NSString *)pathForResource:(NSString *)subpath;

// AppGroupで共有されたNSUserDefaultsを取得
+ (NSUserDefaults*)userDefaults;
@end

AppGroup.m

#import "AppGroup.h"

#define STR(x) @#x
#define STR2(x) STR(x)
static NSString * const kAppIdentifier = STR2(APP_IDENTIFIER);

@implementation AppGroup

+ (NSString *)appGroupID
{
    return [NSString stringWithFormat:@"group.%@", kAppIdentifier];
}

+ (NSString *)pathForResource:(NSString *)subpath
{
    NSString *containerPath = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[self appGroupID]].path;
    return [containerPath stringByAppendingPathComponent:subpath];
}

+ (NSUserDefaults*)userDefaults
{
    return [[NSUserDefaults alloc] initWithSuiteName: [self appGroupID]];
}

@end
12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11