2012年11月1日星期四

[iOS]UITableViewControllerが回転しない

autosizing をチェックした
shouldAutorotateToInterfaceOrientationがYES (Deprecated in iOS 6)
shouldAutorotateもYES (available in iOS 6)
ですが、
画面が回転しない。

悩むところで、
[Application windows are expected to have a root view controller at the end of application launch]の警告に気付いた。

やはりiOS 6では新しい書き方になった:

// [window addSubview:navigationController.view];
window.rootViewController = navigationController;


それて、解決、回転できた。

2012年10月28日星期日

[iOS]古いバージョンのxcodeをinstall

4.5のxcodeから、armv6のsimulatorとコンパイルがもうサポートしないので、必要な場合、古いバージョンのxcodeをインストールしかないみたいだ。
しかし、古いバージョンのxcode 3.2 dmgファイルからinstallすると、xcodeの開発アプリ(xcodetoolset)が新しいOS(10.7以上)ではinstallできない。install内容を指定する時、xcodetoolsetがチェックしていない状態で、変更もできない。

解決方法:
(例の環境 ーー xcode 3.2.5 dmg, Mac OS 10.7.5)
  1. ディスクユーティリティを使って、正式のdmgファイルを書き込みdmgファイルに変換する。
  2. 変換後のdmgファイルをマウントする。
  3. 「Xcode and iOS sdk」ファイルを右クリックして、「パッケージの内容を表示」を選択する
  4. textEditで Contents/iPHoneSDKSL.distファイルを開く
  5. 「10.7」を検索して、「10.8」に変更し、保存する。スクリプトを見ると、現在のシステムOSのバージョンにより大きいならばOKと思う。
今度インストールする時、「xcodetoolset」がチェックしている状態になる。

しかし、結果失敗!!!
インストール最後にクラッシュになって失敗した。
xcode自体は Mac OS 10.7.5には対応しないから。

一番簡単な方法がある:
Xcode 4.3をインストールすればいい、古いiOSバージョンを対応できる。



2012年10月4日星期四

[Android]ActionProvider

おかしかった。

昨日にActionProviderはoptionItemSelectedとうまく共存できなかったのに、今日referenceを読んだ後、何もせずでうまく行った。
referenceのところでこう書いた:
A menu item selection is processed in the following order:
The default implementation does not perform any action and returns false.
つまりdispatchEventみたいに処理順番がある。昨日多分どこかで順番を間違って、ShareActionProviderの動作を上書きした。あり得ないと思うけど、こうで自分の記憶をごまかすしかない。

ちなみに、ShareActionProviderのソースを見て、1番目のonMenuItemClickを使った。

[Android]Android library project作成と使用

最新のEclipse pluginで実験してみた。
Android Projectのproperty 設定の方にisLibraryをチェックすれば、eclipseが勝手にcompileして、jarを作ってくれる。

また使用する時、root folderの直下にlibsのフォルダーを作成して、jarファイルをそこに置いて(assetに入れると、無駄にpackage sizeを増やすだけ)、jarのclassファイルがapkに一緒にcompileするから。

2012年9月24日星期一

[iOS]certification file & provision file について纏め

突然provisionファイルの期限が切れたので、またiOSのアプリ認証手順を思い出すことになった。毎回ネットで調査して、頭の中にあまり整理してないで、手順通りにやるだけで済んだ。今回はちょっと手順の一歩ずつに理由と作用について纏めた。
  1. ローカル認証リクエスト(cerSigningRequest, CSR)ファイル作成。キーチェンアプリから作成したリクエストファイルには、RSA/2048 private key と public keyの情報を含んでいる。このキー情報を使用する前、認証局に承認する必要があるから、直接使うことができない。

  2. 証明書を発行。CSRをprovision管理サイトでuploadして、承認して、今度は証明書を発行してもらう。

  3. 証明書をdownloadして、情報交換キーファイル(p12)を作成。開発する時、アプリをsignするには、private keyも必要なんで、証明書からprivate keyを含んだ認証ファイルを作成。ここで書き出しパスワードの設定が必要なので、保存しとく方がいい。

  4. deviceIDを登録

  5. AppIDを登録

  6. deviceIDとAppIDと証明書をくっ付けって、provisionファイルを作成

  7. 開発PCに(3)の認証ファイルと(6)のprovisionファイルを登録

  8. 開発
纏めて全部で作ったファイルが三つにあった:
  1. リクエストファイル ーー .certSigningRequest
  2. 認証ファイル ーー .cer
  3. キーファイル ーー .p12

2012年9月4日星期二

[Android]FragmentTransactionとbackstackの関係

tabletのために開発したAndroid3.0に初めてFragmentを導入した。目的としては恐らくtabletの画面が大きいなので、Activity遷移する時、毎回全画面をrenderしなければならなくて、非効率だった。そこでFragmentを使って、Activity中の一部だけをrenderすることができる。

Android4.0から小さいなscreenでもFragmentがよく使われている。
最初に一つFragmentが作成られて、Activityの一部として表示される。入れ替わりたい時に、ActivityのFragmentManagerから新しtransactionを作って、入れ替わるの一連の動作を一つtransactionとしてcommitする。commitするまで、画面がrenderしない。

新しいFragmentを画面に表示する動作は、showじゃなくて、常にreplaceというmethodを使用している。
又replaceされたFragmentは現在表示している画面だ、一旦replaceされたら、Fragmentがdetachになる。前のFragmentの状態をそのまま保持したい場合、addToBackStackで新しいFragmentを追加してから、replaceする。しかし、addToBackStackでreplaceした後、更に新しいFragmentをreplaceする場合、popBackStackを使わないと、Stackの一番TopのFragmentだけが入れ替わられる。

2012年8月31日星期五

[iOS]NSURLConnectionのThread問題

NSURLConnectionを利用する場合、Threadの問題を注意する必要がある。
要求によって、http requestに非同期と同期の二つ方式を選択する場合がよくある。

  • 同期
基本はUIThreadに実行される。
UITheadに使う時、connectionWithRequest或はstartを使えば、問題なく送信ができる。
非UIThreadの場合、sendSynchronousRequest或はperformOnMainThread:selector(実はsendSynchronousRequestと同じだと思う)を使う、効果としてはUIThreadに実行していると同じ。

  • 非同期
非同期なので、必ず非UIThreadで実行している。
ここは注意するところ。
一般的に、NSURLConnectionを使用する場合、protocolをimplementする必要がある。なので、そのprotocolに従って定義したmethodを実行するThreadが終了したら、requestも正しく処理できない。異常現象としてはrequestが送信できない、エラーも出ない。これもUIThreadがよく使われる原因だ、UIThreadが終了しないから。
解決策の方法がたくさんあるが、原理は一つだ:何とかして、methodを実行するThreadを死なせないように。例えば、flagを立てってwhile loopを掛ける、或はCFRunLoopRun()とCFRunLoopStopを使うと、処理が完成する。

[Titanium]NSLogによるdebug messageが出力しない問題


昨日自分が作ったTitanium Moduleをテストする時、一部のログが出ない問題が大変だった。一部新規したclassに書いたNSLogがちゃんと出てきたが、linkしたlibraryとして使うsource fileに書いたNSLogが無反応だった。debug flagが漏れたと思ったが、checkしたらちゃんと付いている。
仕方ないTitaniumのsourceを分析する道を選ぶしかない、それて原因を見つけた。簡単に言うとmacroの責だ。
現象と原因は以下のように:

  1. TiProxy或はTiUIViewを承継したclassが問題なく、全部のNSLogを出力した。しかし、NSLogに出力したmessageが<Warning>として出力するはずだったが、<Notice>として出力した。原因はTitaniumの方NSLogをmacroで全部書き直した。Noticeはprintfを使った結果なんだ。
  2. macroを書いたのはTiBase.hだ。このheader fileをimportすれば、ログが全部出る。一つ一つのfileにimportを追加するのは面倒なので、prefix.pchにflagを付けって一気にimportする。
    #ifdef DEBUG
        import "TiBase.h" 
    #endif
    
これですべてのログが出力されるはず。

2012年8月28日星期二

[Titanium]iOSのModule作成

最近ずっとTitaniumの開発を触っている。Titaniumを利用してアプリを作る資料が多かったが、module作成についてはかなり資料が少ない気がする。忘れないために、ここに書き残っておく。

Titaniumをdownloadし、installした後、新規module projectから新しいmoduleを作成し始める。wizardに従って、projectを作成した後、x-code projectが自動に生成する。しかし、作成されたx-code projectが直ぐにコンパイルができない、titanium.xcconfigファイルにtitaniumのpath環境設定の方を確認することがある。moduleにSecurity.frameworkを使う場合、module.xcconfigに

OTHER_LDFLAGS =$(inherited) -framework Security
を追加する。 整った後、moduleのObjective-C codeを作成します。


  1. [TiModule]
  2. defaultとして、TiModuleを承継したクラスが既に自動作成されている。簡単なmethodであれば、このクラスにmember methodを追加して、javascript側から下記の様に使われます。
    var Module = require('xxxModuleId');
    Module.xxxMethod(args); 
    
  3. [TiProxy]
  4. moduleをオブジェクト指向に作りたい場合、TiProxyを承継してクラスを作る作成されたクラスがjavascript側にオブジェクトとして作成られる。referenceに従って、propertyが、member mothodが作った後こうやって利用する。
    var Module = require('xxxModuleId');
    var proxy = Module.createXXXProxy();
    proxy.xxxMethod(args);
    
  5. [TiUIView & TiViewProxy]
  6. UIViewを作成したい場合、TiUIViewとTiViewProxyを承継して、二つのクラスを組合せて作成必要がある。UIViewを実装するのがTiUIViewを承継する方、呼ぶinterfaceとしてはTiViewProxyを承継する方を利用する。
    TiUIViewを承継したクラスにUIViewを定義し、frameSizeChangedに実装する。公開するinterface methodがTiViewProxyに追記する。
  • ExXxxView.h
  • @interface ExXxxView : TiUIView {   
        UiView * mainView;
    }
    @end
    
  • ExXxxView.m
  • @implementation ExXxxView
    -(void)dealloc
    {
        RELEASE_TO_NIL(mainView);
        [super dealloc];
    }
    
    -(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds {
        if (mainView == nil )mainView = new UiView;
        // do something
    }
    @end
    
    これで、javascriptに利用
    var fooView = Module.createView({
        "color":"red",
        "width":20,
        "height":20
    });
    containerWindow.add(fooView);
    
    複数Viewがある場合、上記のdefault method createView()が使えないと思うので、customizeで自分のcreate methodを作る。
  • ExXxxViewProxy.h
  • @interface ExXxxViewProxy : TiViewProxy {
    }
    
    // customize create method
    -(id)createXxxView:(id)args;
    @end
    
  • ExXxxViewProxy.m
  • @implementation ExXxxViewProxy
    -(id) createXxxView:(id)args {
        // return the mainView defined in ExXxxView.h
        return [self view];
    }
    @end
    
    又javascriptに利用
    var fooView = Module.createXxxView({
        "color":"red",
        "width":20,
        "height":20
    });
    containerWindow.add(fooView);
    
    create methodに渡したparametersをproxyにget/setを定義必要がありません、objective-cに直接取ることができる。
    NSInteger intValue = [TiUtils intValue:[self.proxy valueForKey:@"key"]];
    

2012年8月21日星期二

[iOS]duplicate interface declaration

今日 Objective-C のduplicate interface declaration for class XXXの問題に引かれた。
この問題になる原因は三つにまとめた:
  1. #importの代わりに#includeを使用したせいで、重複参照
  2. #同じinterfaceを二回以上定義した
  3. 今度の原因、参照するlibraryのlib.aと共に参照したheader filesの中の一つがlib.aに書き込まれたheader fileとversionが違いそうで、もう一回compileして、導入し解決しました。
追加:
  1. BプロジェクトのソースF1をAプロジェクトにreferenceで参照している場合、F1でimportしたF2がBのF2だ、もしAに同じ名前でF2が存在すれば、エラーになる。BのF1をAにcopyで参照すれば、解決する。

2012年8月20日星期一

[Win]win-shellのescape文字

dos batや、win-shellのエスケープ文字は:
^
例:
echo a=1 ^| b=2
「|」はパイプコマンドですが、ここでは文字としてprintします。

2012年8月19日星期日

[PG]readonlyのclassをinterfaceにするべきじゃない

TitaniumのiOS版 App-In-Purchaseを対応しようとしている、SKProduct, SKPaymentTransactionなとiOS APIが提供しているclassに困った。これらのclassに保存された属性情報全部readonlyになっている。
既存の自作APIソースがそれをそのままinterfaceとして使った。今外から、APIを呼びたいだが、SKProductを直接渡せることができなくて、setすることもできないため、新しいAPIを追加しなければならない。
だからAPIを作る時、パラメータとし、自分がコントロールできないClassをなるべく使用しないことに。

2012年8月18日星期六

[ListView]onItemClick event無効の問題

複数種類のViewを含むcustomizeのitemを持つ ListView がよく使われますが、不注意するとitemのclick eventを監視するOnItemClickListenerが無反応になります。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp" >

    <ImageView
        android:id="@+id/btn_star"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:contentDescription="@string/description_star"
        android:src="@android:drawable/btn_star" />

    <TextView
        android:id="@+id/text_name"
        android:inputType="textMultiLine"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_toLeftOf="@id/btn_share" />

</RelativeLayout>


上記のXML中に問題になったのはTextViewのandroid:inputType="textMultiLine" 。これでClickする時に、FocusをTextViewに奪われる、Item全体のClickEventが無効になってしまう。Touch Eventが全部旨くdispatchされましたが、どうやらlistenerが呼ばれなかった。