もうちょいで完全に咲くゾ
ケビン・スペイシー
悪役もこなす名優ですな。
セブンでの演技もかっちょいいけど、L.Aコンフィデンシャルでの演技がいい。
要minizip。
昔書いたコードで、今はあんま使ってない。
自作のフレームワークには入れてあってちゃんとコンパイルできるのでので、いけるかと。
#import “zip.h”
#import “unzip.h”
#import “zlib.h”
#import “zconf.h”
+ (BOOL)unzipFileAtPath:(NSString *)path
destination:(NSString *)destination
overwrite:(BOOL)overwrite
password:(NSString *)password
error:(NSError **)error
{
zipFile zip = unzOpen((const char*)[path UTF8String]);
if (zip == NULL) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@”Couldn’t open archive.”
forKey:NSLocalizedDescriptionKey];
if (error) {
*error = [NSError errorWithDomain:@”PGUnZipErrorDomain” code:-1 userInfo:userInfo];
}
return NO;
}
unz_global_info globalInfo = {0};
unzGetGlobalInfo(zip, &globalInfo);
if (unzGoToFirstFile(zip) != UNZ_OK) {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:@”Couldn’t move first file in archive.”
forKey:NSLocalizedDescriptionKey];
if (error) {
*error = [NSError errorWithDomain:@”PGUnZipErrorDomain” code:-2 userInfo:userInfo];
}
return NO;
}
BOOL success = YES;
int value;
unsigned char buffer[4096] = {0};
NSFileManager *fileManager = [NSFileManager defaultManager];
do {
if ([password length] == 0)
value = unzOpenCurrentFile(zip);
else
value = unzOpenCurrentFilePassword(zip, [password cStringUsingEncoding:NSASCIIStringEncoding]);
if (value != UNZ_OK) {
success = NO;
break;
}
unz_file_info fileInfo = {0};
value = unzGetCurrentFileInfo(zip, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
if (value != UNZ_OK) {
success = NO;
unzCloseCurrentFile(zip);
break;
}
// 文字エンコーディングは”UTF-8”決めうち
char *filename = (char *)malloc(fileInfo.size_filename + 1);
unzGetCurrentFileInfo(zip, &fileInfo, filename, fileInfo.size_filename + 1, NULL, 0, NULL, 0);
filename[fileInfo.size_filename] = ‘\0’;
NSString *filePath = [NSString stringWithCString:filename encoding:NSUTF8StringEncoding];
free(filename);
if ([filePath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@”/\”]].location != NSNotFound) {
filePath = [filePath stringByReplacingOccurrencesOfString:@”\” withString:@”/”];
}
NSString* fullPath = [destination stringByAppendingPathComponent:filePath];
NSString* directroyPath = [fullPath stringByDeletingLastPathComponent];
if ([[filePath substringFromIndex:[filePath length] - 1] isEqualToString:@”/”]) {
directroyPath = fullPath;
}
if ([fileManager fileExistsAtPath:fullPath] && ! overwrite) {
unzCloseCurrentFile(zip);
value = unzGoToNextFile(zip);
continue;
}
[fileManager createDirectoryAtPath:directroyPath
withIntermediateDirectories:YES
attributes:nil
error:nil];
if (! [fullPath isEqualToString:directroyPath]) {
int read = 0;
FILE *file = fopen((const char*)[fullPath UTF8String], “wb”);
while (file) {
read = unzReadCurrentFile(zip, buffer, 4096);
if (read > 0)
fwrite(buffer, read, 1, file );
else
break;
}
fclose(file);
}
if (fileInfo.dosDate != 0) {
NSDate *currentFileDate = [self convertFromDOSDate:(NSTimeInterval)fileInfo.dosDate];
NSDictionary *attribute = [NSDictionary dictionaryWithObject:currentFileDate forKey:NSFileModificationDate];
[fileManager setAttributes:attribute ofItemAtPath:fullPath error:nil];
[currentFileDate release];
}
unzCloseCurrentFile(zip);
value = unzGoToNextFile(zip);
}
while(value == UNZ_OK && UNZ_OK != UNZ_END_OF_LIST_OF_FILE);
unzClose(zip);
return success;
}
+ (NSDate *)convertFromDOSDate:(NSTimeInterval)dosDate
{
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:1];
[components setMonth:1];
[components setYear:1980];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *sinceDate = [gregorian dateFromComponents:components];
[components release];
[gregorian release];
NSDate *date = [[NSDate alloc] initWithTimeInterval:dosDate sinceDate:sinceDate];
return date;
}
ネタが
#import <CommonCrypto/CommonDigest.h>
- (NSString *)stringByEncryptingInSHA1
{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, data.length, digest);
NSMutableString *sha1 = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
[sha1 appendFormat:@”%02x”, digest[i]];
}
return sha1;
}
ネタが無いようぅぅ
- (NSString *)stringByEncryptingInMD5
{
const char *cStr = [self UTF8String];
unsigned char result[16];
CC_MD5( cStr, strlen(cStr), result );
return [NSString stringWithFormat:
@”%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X”,
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
];
}
ARやりたくて、買った。
サンプルプログラムのできはアレですが、6軸センサの解説なんかはわかりやすくて、とても参考になった良書だと思います。
んが、この本、せっかく面白い分野で、いろいろ解説されていて、内容や目の向け方はすごくいいのに、誤字が多すぎる。
著者や関係者はちゃんとチェックしたんだろうか。。すぐに見つかるのに。著者なんか3名もいるのに・・
これではせっかくいい内容が、最近多い、「片手間で小遣い稼ぎ的に作ってみたホジホジ」的な本として映ってしまう。サンプルプログラムも全く実用性なんかないので、余計に・・(⌘+shift+Bした?ってかんじのプログラムなんで・・)。
P231なんかは「まじ、確認した?」って感じです。
こんな評価もされちゃってて、実にもったいない。
Push通知の日本語情報はいろいろあるっすね。
ま、ここがよく見るところではないかと。
よくまとめられてるし、この通りやれば、実現はできる。
んが、肝心のPush通知について理解し難い。
その原因は、記事が悪いのではなく、Push通知実現にはステップが多いから。
しかも、作業中に一時ファイルがたくさんできてしまうので、記事にあるようにツラツラやっていくだけだと、なんのために作業しているのか途中で分からなくなる。
なので、もちっと詳しくまとめてみた。
要は、Push通知の実現に必要なのは、以下のもの。
サーバー側
iOSアプリ側
3つとも、「App ID」に紐付いていないといけないので、まずは「App ID」を作る。
「App ID」作成手順
1. ADCへログイン
「iOS Provisioning Portal」ページヘ。
2. 「App IDs」ページで新たにアプリのIDを作成
「New App ID」というボタンがあるので押すと入力フォームページが表示される。
各項目は以下のように入力。
・Description
→アプリの名前を入力(「App IDs」のトップ画面のリストに表示される)
・Bundle Seed ID (App ID Prefix)
→取り敢えず「Use Team ID 」を選択
・Bundle Identifier (App ID Suffix)
→「com.tumblr.j7lg.アプリ名」などと入力
3. 「Submit」で送信
入力確認の画面はないので慎重に。
完了後、「App IDs」のトップ画面が表示される。
次にサーバーで必要な証明書チェーンとRSAの鍵を作る。
「iOS Provisioning Portal」ページも必要なので、ブラウザはそのまま。
サーバーに必要なファイルの作成
1.キーチェーンアクセスで認証局に証明書を要求するファイルを作成
キーチェーンアクセスを起動。
メニューの「キーチェーンアクセス>証明書アシスタント>認証局に証明書を要求」を選択して、証明書アシスタントを起動。
ダイアログでは以下のように入力。
・ユーザーのメールアドレス
→自分のメールアドレス
・通称
→自分の名前もしくは組織名など
・CAのメールアドレス
→空欄のまま
・要求の処理
→ディスクに保存
「保存」を押して、適当な場所に保存。
2. 該当のApp IDの「Configure」リンクへ
「Enable for Apple Push Notification service」のチェックを入れると「Configure」ボタンがアクティブになる。
「Configure」ボタンを押下し、先程作った「認証局に証明書を要求するファイル」をアップロード。
「Development」と「Production」で同じ事をやる。
「認証局に証明書を要求するファイル」はこの時点で捨てていい。
一旦「App IDs」のトップ画面に戻って、再度、該当のApp IDの「Configure」リンクへ行くと、「Action」が「Download」に変わっているので、ダウンロードして保存(aps_development.cer, aps_production.cer)しておく。
3. 証明書をキーチェーンに一旦登録
このステップは、P12(PKCS#12)に変換するためで、opensslコマンドで置き換えられるけど、GUIの方が手軽なので、キーチェーンを利用しているってだけ。
保存した証明書をダブルクリックでキーチェーンに登録する。
キーチェーンの「自分の証明書」を表示し、リストに以下の2つの名前があるか確認。
「Apple Development IOS Push Services:アプリのバンドルID」
「Apple Production IOS Push Services:アプリのバンドルID」
4. 登録した証明書をP12(PKCS#12)で書き出す
「Apple Development IOS Push Services:アプリのバンドルID」を選択して、「ファイル>書き出す…」を選択。
ファイル名を「APNsDevelopmentCert.p12」などとして保存。
「Apple Development IOS Push Services:アプリのバンドルID」の左のトグルを展開して、鍵アイコンが付いた行を選択。
同様に「ファイル>書き出す…」を選択して、「APNsDevelopmentKey.p12」などとして保存。
Productionの方も同様に作業する。
この時点で、キーチェーンに登録している証明書は登録解除して構わない。
5. P12をPEMに変換する
サーバーで扱いやすいよう、以下のコマンドでPEM形式に変換する。
openssl pkcs12 -clcerts -nokeys -out APNsDevelopmentCert.pem -in APNsDevelopmentCert.p12
openssl pkcs12 -nocerts -out APNsDevelopmentKey.pem -in APNsDevelopmentKey.p12
openssl rsa -in APNsDevelopmentKey.pem -out APNsDevelopmentKeyRSA.pem
cat APNsDevelopmentCert.pem APNsDevelopmentKeyRSA.pem > APNsDevelopmentChain.pem
Productionの方も同様に作業する。
「*RSA.pem」と「*Chain.pem」以外のファイルは捨てて構わない。
次にアプリに必要なプロビジョニングファイルを作成する。
「iOS Provisioning Portal」ページも必要なので、ブラウザはそのまま。
iOSアプリに必要なファイルの作成
1. 「Provisioning」ページで、まずは開発用に、新たにプロビジョニングファイルを作成
「New Profile」というボタンがあるので押すと入力フォームページが表示される。
各項目は以下のように入力。
・Profile Name
→「アプリの名前+Development」などと入力(「Provisioning」のトップ画面のリストに表示される)
・Certificates
→開発者証明書のこと
XcodeのCode Signingに使われるもので、開発機のキーチェーンアクセスに登録されているはず
・App ID
→新しく作った該当の「App ID」を選択
・Devices
→開発用として利用する端末を選択
Productionの方もほぼ同様に作業する。
2. プロビジョニングファイルのダウンロード。
一旦「iOS Provisioning Portal」のトップ画面に戻って、再度「Provisioning」にいくと、「Action」が「Download」に変わっているので、ダウンロードして保存しておく。
3. Xcodeを立ち上げ、オーガナイザでプロビジョニングファイルを取り込む
この時点でダウンロードしたファイルは捨てて構わない。
以上っす。
なっがい・・・
iOS向けのlibssl.dylibがなくなったそうで、自前でコンパイルしないといけない。
ググればすぐ見つかるけど、このスクリプトを使うと便利。
ソースがなければダウンロードもしてくれるので、このスクリプト1本でおけ。
正常にコンパイルが終わったら、以下のように使う。
ポイントは、ssl.h内で<openssl/〜〜.h>とインクルードされているので、opensslフォルダごとコピーすること。
3G対応の自作アプリのコードで、先日作ったフレームワークを採用してみたところ、ユニバーサルバイナリにarmv6用が含まれていない事が判明。
んで、TARGETのArchitectureにarmv6を入れてみたけど、”arm/types.h”がないと怒られる・・こまった。
シェルスクリプトを見てみると、以下のコマンドの部分でエラーが出てしまう。
xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator${IPHONEOS_DEPLOYMENT_TARGET} -target “${PROJECT_NAME}” -configuration “${CONFIGURATION}” clean build
問題となっているのは以下のパスのファイルで、シミュレータSDKのものだ。そらないわな。
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/usr/include/machine/types.h
なぜか、armv6をシミュレータSDKでコンパイルしようとしているみたい。
なんでこんなことになるかは不明・・ワシの環境だけ?2台の開発機で試したんだけど・・
ごちゃいっても仕方ないので対応する。
方法としてはプロジェクトの設定で、Configurationsを切り分け、設定を変更することにした。
手順は以下のとおり。
なお、その他の設定はこのページ通りで、変更した箇所だけ。
Configurationsのコピー&リネーム
「PROJECT > Info > Configurations」で、「+」を押し、「Debug」をコピーし、「Simulator」と名前を変更する。
Architecturesの設定
「TARGET > Build Settings > Architectures」を以下のように設定。
Debug ・・・・・ armv6 $(ARCHS_STANDARD_32BIT)
Simulator ・・・ $(ARCHS_STANDARD_32BIT)
Valid Architectureの設定
「TARGET > Build Settings > Valid Architecture」をすべて「armv6 armv7 i386」に設定。
[番外メモ]カテゴリ用のフラグ設定
フレームワークを取り込んだ先のプロジェクトで、フレームワーク内のカテゴリメソッドを呼び出すとエラーが起きていたので、「TARGET > Build Settings > Other Linker Flags」を「-ObjC -all_load」に変更した。
シェルスクリプトの変更
Aggregateで作ったTARGETのシェルスクリプトで、シミュレータSDKを使う箇所の、「${CONFIGURATION}」変数を「Simulator」に変更する。
使っているスクリプトを参考までに。
(コピペするときはシングルクォート、ダブルクォートに気をつけてください)
# Environment Variables
FRAMEWORK_NAME=${PROJECT_NAME}
FRAMEWORK_VERSION=A
FRAMEWORK_VERSION_NUMBER=1.0.0
FRAMEWORK_BUILD_PATH=”./build/${CONFIGURATION}-framework”
FRAMEWORK_DIR_NAME=”${FRAMEWORK_NAME}.framework”
FRAMEWORK_PACKAGE_NAME=”${FRAMEWORK_NAME}.${FRAMEWORK_VERSION_NUMBER}.zip”
# Clean directories
cd “${SRCROOT}”
rm -rf “${FRAMEWORK_BUILD_PATH}”
# Build simulator and device binaries.
xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator${IPHONEOS_DEPLOYMENT_TARGET} -target “${PROJECT_NAME}” -configuration “Simulator” clean build
[ $? != 0 ] && exit 1
xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos${IPHONEOS_DEPLOYMENT_TARGET} -target “${PROJECT_NAME}” -configuration “${CONFIGURATION}” clean build
[ $? != 0 ] && exit 1
# create framework directories.
mkdir -p “${FRAMEWORK_BUILD_PATH}”
cd “${SRCROOT}/${FRAMEWORK_BUILD_PATH}”
mkdir -p “${FRAMEWORK_DIR_NAME}”
mkdir -p “${FRAMEWORK_DIR_NAME}/Versions”
mkdir -p “${FRAMEWORK_DIR_NAME}/Versions/${FRAMEWORK_VERSION}”
mkdir -p “${FRAMEWORK_DIR_NAME}/Versions/${FRAMEWORK_VERSION}/Headers”
mkdir -p “${FRAMEWORK_DIR_NAME}/Versions/${FRAMEWORK_VERSION}/Resources”
# create symlinks
cd “${SRCROOT}/${FRAMEWORK_BUILD_PATH}/${FRAMEWORK_DIR_NAME}”
ln -s “${FRAMEWORK_VERSION}” “Versions/Current”
ln -s “Versions/Current/Headers” “Headers”
ln -s “Versions/Current/Resources” “Resources”
ln -s “Versions/Current/${FRAMEWORK_NAME}” “${FRAMEWORK_NAME}”
# create the universal library
cd “${SRCROOT}”
lipo “${SRCROOT}/build/${CONFIGURATION}-iphoneos/lib${FRAMEWORK_NAME}.a” \
”${SRCROOT}/build/Simulator-iphonesimulator/lib${FRAMEWORK_NAME}.a” \
-create -output \
”${SRCROOT}/${FRAMEWORK_BUILD_PATH}/${FRAMEWORK_DIR_NAME}/Versions/Current/${FRAMEWORK_NAME}”
# copy files
files=$(echo ${SRCROOT}/build/${CONFIGURATION}-iphoneos/Headers/*.h)
[ “x${files}” != ‘x’”${SRCROOT}”/build/”${CONFIGURATION}”-iphoneos/Headers/\*.h ] && \
cp “${SRCROOT}”/build/”${CONFIGURATION}”-iphoneos/Headers/*.h “${SRCROOT}/${FRAMEWORK_BUILD_PATH}/${FRAMEWORK_DIR_NAME}/Headers/”
cp “${SRCROOT}/${PROJECT_NAME}/Info.plist” “${SRCROOT}/${FRAMEWORK_BUILD_PATH}/${FRAMEWORK_DIR_NAME}/Resources”
# zip (For distribute)
cd “${SRCROOT}/${FRAMEWORK_BUILD_PATH}”
zip -ry ${FRAMEWORK_PACKAGE_NAME} ${FRAMEWORK_DIR_NAME}
テスト
ビルドしてみて、出来上がったバイナリをfileコマンドで見てみる
バイナリのパスは
build/Debug-framework/${PROJECT_NAME}.framework/Versions/A/${PROJECT_NAME}
出力が、以下のようになればおけ。
ファイルパス Mach-O universal binary with 3 architectures
ファイルパス (for architecture armv6): current ar archive random library
ファイルパス (for architecture armv7): current ar archive random library
ファイルパス (for architecture i386): current ar archive random library
ネタがなさすぐる
- (BOOL)isValidEmail
{
NSString *regex = @”[a-zA-Z0-9!#$%&’*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&’*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?”;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@”SELF MATCHES %@”, regex];
return [predicate evaluateWithObject:self];
}
NSPredicateとか単純なマッチングには便利っすね。
コピペするときはシングルクォーテーションとダブルクォーテーションを打ち替えてくださいな。(tumblrが変換しちゃうんで・・)
まぁ需要ないか
(出典: planet--earth.ca、cliqueclogsから)