2014年11月28日金曜日

UIWebViewのzoomScale


UIWebViewのzoomScaleプロパティーzoomScaleでは、その時点のzoomScaleを得ることができない。
UIWebViewDelegateのscrollViewDidEndZoomingで通知されるscaleを保存しておく。

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView
                                    withView:(UIView *)view atScale:(float)scale
{
    NSLog(@"Zoomscale %f",scale);
}


iOS8 Enterpriseアプリ配布 (OTA) でインストールできない


Enterpriseアプリ配布でiOS8でインストールが完了しなくなりました。
どうやらprovisioning profileになんらかの問題が発生しているようです。

まずはデバイスの再起動を試す。(もしかしたらSafariの再起動だけでもよいか?
いろいろ設定を変えて試したあとは、ときどき再起動してみるのがよいでしょう。

Xcode>Preference>Accounts>View Details...でprovisioning profilesを同期し、期限切れ等がないかチェック。

plistのアイコンのパスに誤りがないがチェック。full-size-imageのパスに誤りがあるとインストールが完了しないようです。


MIME type に application/octet-stream が設定されているかチェック。なければ追加。これが必須か確認していませんが、やっておいて損はないでしょう。

デバイスをMacに接続し、コンソールログを見ながらインストールを実行し、インストール中に発生しているエラーなどをチェックする。
Xcode ⇨ Window ⇨ デバイス選択 ⇨ 右ペイン左下の△アイコンクリック

itunesstored[1016] <Warning>: LoadExternalDownloadManifestOperation: Ignore manifest download, already have bundleID: {bundleID}

このエラーが出ている場合はplistの設定を変更してもそれを読み込んでくれないようです。
plistのbundle-identifierを一時的に変更(末尾に"temp"を追加するなど)し、インストール再実行。このエラーが出なくなったらbundle-identifierを元に戻す。
私は試していませんが、一般>リセット>ホーム画面のレイアウトをリセットでも対処できるようです。
参考: iOS 8 - Can't Install Enterprise App

以下のようなエラーが見つかりましたが、provisioning profileになんらかの問題があることが起因していると思われます。
XcodeのGeneral>Team、Build Settings>Code Signingの設定をチェックし、再ビルドを行う。Xcode5の場合はXcode6でビルドしてみる。

<Notice>: flow_divert_token_set (0): Failed to get the key unit from the token: 22
<Error>: Could not set socket option SO_OPPORTUNISTIC: Invalid argument


<Warning>: LSInstallProgress: In observeValueForKeyPath:fractionCompleted could not find parent progress for {app-url}, it may have been removed

<Error>: 0x101ccc000 -[MICodeSigningVerifier performValidationWithError:]: 186: Failed to verify code signature of <MIExecutableBundle : path = /private/var/mobile/Library/Caches/com.apple.mobile.installd.staging/temp.HCjGx1/extracted/Payload/MyApp.app identifier = {appID} type = 4> : 0xe8008015 (Signer did not match any installed provisioning profile)
<Error>: 0x101ccc000 -[MIInstaller performInstallationWithError:]: Verification stage failed

参考: <Error>: Could not set socket option SO_OPPORTUNISTIC


まだダメな場合は、デバイスを再起動してみる。

ついでながら、Xcode6.1に新規にデバイスを追加したときに”digest is missing”のエラーが発生しました。
接続時になんらかのdigestが作成されるが、それがすぐにはXcodeに反映されない、といったところでしょうか。

Xcode を再起動、iPhone を再接続で解決します。

2014年11月16日日曜日

YosemiteにアップデートしたらMailがクラッシュする

YosemiteにアップデートしたらMailがクラッシュする

YosemiteにアップデートしたらMailがクラッシュするようになりました。
こんなエラーメッセージが出ます。
Terminating app due to exception while holding database lock 'NSInternalInconsistencyException',

私の場合はインターネットアカウントでメールアカウントを一旦無効にすると起動するようになり、順次アカウントを有効にすることで戻すことで回復しました。問題のあるアカウントが有効になっていると、クラッシュが再発します。

参考: Fix Mail crashing after upgrading to Yosemite

Mailをセーフモードで起動する方法も書かれています。
Mail起動直後にシフトキーを押し、起動が完了するまで押し続けます。ウインドウが表示されてもすぐにはシフトキーを離さず、初期化が完全に終わるのを待ちます。
通常は前回選択されていたメールが選択状態になりますが、セーフモードの場合は未選択状態で起動します。前回選択されていたメールがエラーの原因の場合に有効です。
私の場合もこれで一回だけ回復したのですが、しばらくしたらクラッシュが再発するようになりました。

OSをセーフモードで起動し、iMailのウインドウ位置などを保存したデータを消す、という方法も書かれています。この保存データに問題がある場合に有効です。
・アプリ起動時にチャイム音直後にシフトキーを押し、しばらく押し続ける。
・起動後、Finder>移動でメニューを表示、optionキーを押しながらLibrayを選択。
・Containers > com.apple.mail > Data > Library > Saved Application State folderへ移動。
・com.apple.mail.savedStateを削除。

Xcode process launch failed: Security

新しいiPhone6に開発中のアプリをインストールしたらこんなエラーでアプリが起動できない。
Xcode process launch failed: Security

このメッセージが出る場合、アプリはすでにデバイスにインストールされている。
アプリアイコンをタップすると、アプリ起動を許可するか警告が出るので、"yes"とすると起動が可能になる。

参考: Xcode process launch failed: Security



2014年9月26日金曜日

今後も利用しそうなリンクのメモ

今後も利用しそうなリンクのメモ

Fix Mail crashing after upgrading to Yosemite
Mailのクラッシュ対策。
YosemiteにアップデートしたらMailがクラッシュするようになりました。こんなエラーメッセージが出ます。
Terminating app due to exception while holding database lock 'NSInternalInconsistencyException',

インターネットアカウントでメールアカウントを一旦無効にすると起動するようになり、順次アカウントを有効にすることで戻すことで回復しました。問題のあるアカウントが有効になっていると、クラッシュが再発します。

Mailをセーフモードで起動する方法も書かれています。
Mail起動直後にシフトキーを押し、起動が完了するまで押し続けます。ウインドウが表示されてもすぐにはシフトキーを離さず、初期化が完全に終わるのを待ちます。
通常は前回選択されていたメールが選択状態になりますが、セーフモードの場合は未選択状態で起動します。前回選択されていたメールがエラーの原因の場合に有効です。
私の場合、これで一回は回復しましたのですが、しばらくしたらクラッシュが再発するようになり、上記のアカウント無効化を行いました。

OSをセーフモードで起動し、iMailのウインドウ位置などを保存したデータを消す、という方法も書かれています。この保存データに問題がある場合に有効です。
・アプリ起動時にチャイム音直後にシフトキーを押し、しばらく押し続ける。
・起動後、Finder>移動でメニューを表示、optionキーを押しながらLibrayを選択。
・Containers > com.apple.mail > Data > Library > Saved Application State folderへ移動。
・com.apple.mail.savedStateを削除。

もう使わなくなったアプリアイコンを整理したいときに便利。

iOS:パスコードを忘れた、またはデバイスが使えなくなった場合
パスコードを何回か間違えるとデバイスがロックされます。そんな場合の対応ですが、何通りかあるものの、要はデバイスを初期化するかバックアップに復帰するというもので、同期しているiTunesにログインできるか、iCloudにログインできる必要があります。

iTunes 11.1 deleted almost all of my music! WHY?
Re: what happened to my playlists? 
iTunesのアップデートが問題だったのか、iTunesライブラリの引っ越しをしたのが原因なのか、iPhoneからMusicが全部消えてしまい、何度同期を繰り返してもMusicがコピーされなくなりました。
”iTunes Library.itl”を"Previous iTunes Libraries"中のバックアップで置き換えるという方法が紹介されていますが、私の場合には回復しませんでした。

iTunes:iTunes ライブラリおよびプレイリストを作成し直す方法
置換前の”iTunes Library.itl”に再度戻すと回復しましたが、もしかしたら”iTunes Library.itl”が壊れて、初期化されたのかもしれません。
”iTunes Library.itl”を削除すれば、再作成されて回復するようです。

iTunes ライブラリを外付けドライブにコピーしてバックアップする
iTunesライブラリのバックアップ、およびそれからの回復方法。
バックアップをコピーし、iTunesをoption キー (Mac) または Shift キー (Windows) を押したまま、iTunes を起動し、ライブラリの場所を再指定する。

フォトライブラリーがまだ利用可能になっていないため、iPhone...に写真を同期できません。
「iPod Photo Cache」フォルダを削除してみる。
手順詳細は"「iPod Photo Cache」フォルダについて"参照。

2014年9月23日火曜日

IOS 8 でのApp提出

iTunesが様変わりしていて、App提出で手こずりました。

こちらのブログにスクリーンショット付きで手順が紹介されています。
新しいiTunesConnectで困ったこと

メッセージがわかりづらいので若干補足しておきます。

最初に出くわすメッセージ:
You must submit your builds using Xcode 5.1.1 or later, or Application Loader 2.9.1 or later. 
After you’ve submitted a build, select it in the Builds section below.
『「評価」セクションで、Apple コンテンツ説明の頻度レベルを選択する必要があります。』

『「評価」セクションとなっているが「レーティング 編集」
Appleコンテンツ説明」は「Appleコンテンツの詳細」(「Apple」は「App」の誤り?)。

「Appleコンテンツの詳細」で「無制限のWebアクセス」を「はい」にすると対象年齢が17+になります。
UIWebViewを使っている場合はiOS設定の機能制限が適用されるので、Webアクセス制限可能ではあります。

ITC.apps.validation.prerelease_build_missing
このメッセージと「After you’ve submitted a build, select it in the Builds section below.」がペアになるべきででしょう。
「ビルド」をクリックするとSubmitしてあるビルド一覧が表示され、レビュー対象を選択するようになっています。










2014年8月29日金曜日

UIWebViewとアプリの連携


UIWebViewDelegateの shouldStartLoadWithRequest を使ったアプリとの連携例を、先日アップした"UIWebViewで閲覧中のページ内の検索"に追加しました。
サンプルコードダウンロード: TheSearcher2

shouldStartLoadWithRequestはページ移動が発生したときに呼ばれ、基本的には移動を許すかどうかを判断するものですが、ここでアプリの処理を追加することができます。

リンク先のURLをrequestから取得し、それに基づいて処理を行います。
TheSearcher2にhashとprotocolを利用してアプリへの処理要求かどうかを判断し、JavaScriptでUIWebViewに表示する例を加えてあります。

・アイコンイメージをタップ
protocol=file://でurl末尾が".png"
アイコンイメージをstringByEvaluatingJavaScriptFromStringで切替

・"Home Directory"をタップ
protocol=file://でhash="#homedir"
NSHomeDirectory()内のフォルダ一覧を作成し、stringByEvaluatingJavaScriptFromStringでdirDiv内に表示。
各フォルダの情報は<a>タグに設定、hrefにフルパスをセット。
protocolは"filename://"とする。

・フォルダ一覧のリンクをタップ
protocol="filename://"
パス内のファイル、フォルダ一覧をstringByEvaluatingJavaScriptFromStringでdirDiv内に表示。

上記の場合に、NOを返し、ページ移動はキャンセルする。







2014年8月22日金曜日

warning: no rule to process file ... of type sourcecode.javascript

JavaScriptなどコンパイル対象でないファイルをプロジェクトに追加したとき、
no rule to process file ... of type ...というエラーが発生する。

warning: no rule to process file '/Users/..../UIWebViewSearch.js' of type sourcecode.javascript for architecture i386

プロジェクトのBuild Phases > Complie Sources から当該ファイルを削除する。

UIWebViewで閲覧中のページ内の検索

UIWebViewで閲覧中のHTML内で文字検索をしたいと思い、なにかいい方法がないか探したところ、サンプルアプリを添付してくれているページがありました。
第一のポイントはstringByEvaluatingJavaScriptFromString:の使い方で、てっきりHTMLに既にあるscriptの呼び出しに使うかと思っていたのですが、この引数で渡すjavascriptHTML Documentに適用して結果を返してくれる、つまりscriptを事実上追加することができるのです。このjavascriptで適用した変数(var)やfunctionは、それ以降のメソッド呼び出しで使用することができ、グローバル変数は値も保持されます。

このサンプルのJavaScriptをもう少し単純化できないか試したのですが、書き直してはいるものの、ハイライト部分はほとんど同じ方法になっています。

このサンプルを基に作成したTheSearche2をアップします。
TheSearcher2

TheSearche2はオリジナルに次のような変更を加えています。

Storyboardを使用。
検索ヒット箇所の前後移動を追加。
初期HTMLをGoogle、Yahoo、Bingへのリンクとし、実際のWebページ内での検索を実行。
UIWebViewのサブクラスをdelegateを使用する方法に変更。

UIWebViewのドキュメントには"The UIWebView class should not be subclassed."と書かれています。

このサンプルには"UIWebViewとアプリの連携"のコードも含まれています。

2014年4月3日木曜日

UIView小技集


  1. UIViewの罫線
    drawRectで描画することもできますが、こんな簡単な方法で可能でした。
    //↓赤枠を2ptで描画
    [view.layer setBorderColor:[UIColor redColor].CGColor];
    [view.layer setBorderWidth:2.0];
    (UIViewに枠線を付ける方法からのコピペです。)

    角を丸くする場合
    view.layer.cornerRadius = 10;
     
  2. UILabelのサイズをtextに合わせる
    CGFloat padding = 4;
    CGSize size =
       [aL
    abel.text sizeWithAttributes:@{NSFontAttributeName:aLabel.font}];
    aLabel.frame = CGRectMake(aLabel.frame.origin.x,                                              aLabel.frame.origin.y,
                                                  size.
    width + padding*2,
                                                  size.
    height + padding*2);
  3. UILabel内の文字マージン調整
    UILabelのサブクラスでdrawTextInRectをオーバライド
    - (void)drawTextInRect:(CGRect)rect
    {
        rect.origin.y += 2;
        [super drawTextInRect:rect];}
     
  4. Viewの拡大/縮小
    例: aViewを縦横1.5倍に拡大
    CGFloat scaleX = 1.5;
    CGFloat scaleY = 1.5;
    CGAffineTransform tr =
                   CGAffineTransformScale(aView.transform, scaleX, scaleY);
    aView.transform = tr;






2014年3月30日日曜日

Certificate期限切れの通知が送られてきたら


こんなメールが送られてきたら...
Your iOS Distribution Certificate will expire in 30 days.

  • メール内の"Certificates, Identifiers & Profiles"リンクをクリック
    • またはMember Center > Certificates, Identifiers & Profiles > iOS Apps > Certificates
  • iOS App > Certificatesへ移動
  • +をクリックしてCertificateを追加
    追記:Xcode7のPreferencesでCertificateに"Create"ボタンが表示される。これのクリックで以下の数ステップが実行されるかも...
  • 期限が切れるCertificateを選択してContinue
    • Development > iOS App DevelopmentContinue
    • Deployment > App Store or Ad Hoc Distribution
  •  以前に使用したCertificateSigningRequest.certSigningRequestを保存してあればそれをアップロード、なければキーチェインアクセス > 証明書アシスタント > 認証局に証明書を要求... で作成してアップロード
  • Certificate ReadyになったらダウンロードダウンロードしたCertificateをダブルクリック
  • Member Centerで更新されたCertificateが追加されていることを確認
  • XcodeのPreferences... > Account > View Details...を開き、左下の丸矢印アイコンクリックで同期
    追記:Xcode7では丸矢印アイコンなし、代わりにDownload Allボタン。Provisioningを更新すると当該項目にDownloadボタンが表示される。
  • 期限切れになるCertificateを使用しているProvisioningを更新
    • Member Center>Certificates, Identifiers & Profiles>
      iOS Apps>Provisioning Profiles
    • 対象Provisioningを選択
    • Edit
    • Certificateを更新後のものに変更
    • Generate
  • XCodeのPreferences... > Account > View Details...で同期
  • 必要なものの期限が全て更新されたことを確認。


Mailアタッチメントのインポート

Supporting Files > ...-info.plistを選択

Information Property Listの+をクリックし、Document typesを追加

Document typesにサポートするDocument Content Type UTIsを追加

ここまででMail添付のファイルをプレスしたときにこのアプリのアイコンも表示されるされるようになる。

AppDelegateにapplication:openURL:sourceApplication:メソッド追加
他のアプリからファイルオープンで起動またはアクティベイトされた場合に呼ばれる。
メソッドが呼ばれたとにきには既にInboxにインポートするファイルがコピーされている。
- (BOOL)application:(UIApplication *)application
                                openURL:(NSURL *)url
                  sourceApplication:(NSString *)sourceApplication
                             annotation:(id)annotation
{
    //url=コピーされたファイルのURL
}

Inboxディレクトリの場所
NSString *inboxDir = [NSString stringWithFormat:@"%@/Documents/Inbox", NSHomeDirectory()];

Inbox内のファイルリスト

NSFileManager *fileManager = [NSFileManager defaultManager];

NSArray *files = [fileManager subpathsAtPath: inboxDir];

テキストファイルの場合
NSStringEncoding enc;
NSString *inboxText = [NSString stringWithContentsOfFile:fullPath usedEncoding:&enc error:&err];

参考: Registering the File Types Your App Supports

カスタムタイプ追加例

  • ExporTTypeUTIsを追加。子要素が自動的に追加される。
  • Conforms to UTIsに親定義を設定。ここではpublic.plane-textを選択。
  • identifierにユニークな識別子を設定。
  • Equivalent Typesにpublic.filename-extensionを追加し、拡張子を設定。
  • Document Types/Document Content Type UTIsにItemを追加し、上記identifierを設定する。

2014年3月18日火曜日

iOS: 7.1対応 自己署名証明書でのEnterpriseアプリ配布


Enterpriseアプリ配布でこんなエラーに出会ったら...
 ”....”の証明書が有効ではないため、Appをインストールできません。
 ...に接続できません。

iOS7.1からEnterprise配布がHTTPSでないとインストールできなくなりました。
apacheを自己署名証明書で構成した場合は信頼できない証明書のため、HTTPSでもインストールできません。

iOSデバイスでは"...に接続できません"とそっけなく表示されますが、デバイスをMacに接続し、コンソールログを見るとエラーの理由が分かります。
Xcode ⇨ Window ⇨ デバイス選択 ⇨ 右ペイン左下の△アイコンクリック


itms-services:プロトコルに従ってurl先のplistをダウンロードするときにサーバ証明書が信頼できないエラーが発生しています。safariで直接plistをダウンロードするのであれば、ここで警告が表示され、サーバを信頼すればダウンロードを継続できますが、インストーラの場合は"...に接続できません"を表示して継続できなくなります。

いろいろ試した結果、iPhone Configulatorでサーバのcrtファイルをインストールするmobileconfigを作り、これをメールかWebで配布、各デバイスにインストールするのが順当なようです。

Apple Configuratorではmobileconfigを出力できないようなので、少し古いですがiPhone Configuratorを使いました。

実はhttpsが必要なのはplistのダウンロードだけなので、plistをパブリックな場所に置いてもよれけば、Enterprise app deployment doesn't work on iOS 7.1で紹介されているdropboxのhttpsを利用する方法もあります。

plistだけdropboxに置き、itms-services://?action=download-manifest&url=http:...のリンク先をdropboxからのファイルダウンロードのURLにすることで、インストールが可能になります。
plist内のリンクは社内LANのURLにしておけば、plistをパブリックにしても社外からアプリをインストールすることはできません。

dropboxでなくともiOSに含まれている認証局の証明書であればよいので、自社のSSLサーバにplistだけ置くという方法もあります。

2014年2月10日月曜日

staticライブラリで追加したCategoryのメソッドがunrecognized selectorになる

staticライブラリにCategoryで既存クラスにメソッドを追加し、それを別プロジェクトでリンクしようとしたが、コンパイルは通るが実行時にunrecognized selectorでエラーとなる。
Objective-Cはダイナミックバインディングを行うため、個々のクラスにはリンカーシンボルが設定されるが、個々のメソッドには設定されない。スタティックライブラリでカテゴリにより既存クラスを拡張した場合、リンカーは関連づく基クラスのメソッドが分からず、このエラーとなる。
プロジェクトのBuild Settings/Linking/Other Linker Flagsに-ObjeCフラグを追加すると回避できる。

このオプションにより、当該ライブラリ中のObjective-Cのクラス/カテゴリが定義されているオブジェクトファイルが全てロードされる。
不要なものもロードされることになり、実行ファイルがフラグなし時より大きくなることが多い。
スタティックライブラリ中のクラス/メソッドの多くが必要な場合は問題ないでしょうが、ほんの一部しか利用しない場合は、ライブラリの構成を見直した方がよいでしょう。

参考: