Provisioning Profileを変えても駄目で、Xcode5の事例で出てたrestartも駄目で開発機再起動も駄目で何度やっても弾かれるしどうしようもなくなってたが、Application loaderを使うことで解決。
https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide_Jpn/Chapters/SubmittingTheApp.html#//apple_ref/doc/uid/TP40014483-CH33-SW8
Organizerでipaにexportして(Save for iOS App Store Deployment)、Application Loaderからアップロードするとそのままアップロード出来た。
というか、新生TestFlightはなぜあんな処理に時間かかるのか。アップロード完了してからアクティブになるまでひどい時だと30分くらいかかる。
2014年12月16日火曜日
2014年12月4日木曜日
単一Fragmentを表示するActivityの共通化
全画面想定のFragmentをActivityで取り回したい場合。AaaFragment, BbbFragmentに合わせてAaaActivity, BbbActivityとか作るのは面倒なのでActivityのWrapperを共通化。
Fragmentは public static XxxFragment newInstance(Bundle args);を実装している想定。
画面遷移時は、FragmentからならWrapperActivity.openFragmentActivity(getActivity(), SecondFragment.class, secondFragmentsArguments); という感じで行える。
Fragmentは public static XxxFragment newInstance(Bundle args);を実装している想定。
画面遷移時は、FragmentからならWrapperActivity.openFragmentActivity(getActivity(), SecondFragment.class, secondFragmentsArguments); という感じで行える。
package hoge.fuga.activities; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.View; import android.view.View.OnClickListener; import jp.arithmetic.arithmusic.R; import jp.arithmetic.arithmusic.model.FragmentReplacer; public class WrapperActivity extends Activity { public static final String TAG = "WrapperActivity"; public static final String ARGS_FRAGMENT = "app-fragment"; /** * 1つのFragmentを全面に表示する共通化Activity * @param fromActivity * @param clazz * @param args */ public static void openFragmentActivity(Activity fromActivity, Class clazz, Bundle args) { // setup bundle if (args == null) { args = new Bundle(); } args.putString(ARGS_FRAGMENT, clazz.getName()); // setup intent Intent i = new Intent(fromActivity, WrapperActivity.class); i.putExtras(args); // start activity fromActivity.startActivity(i); } /** * close * @param fromActivity */ public static void closeFragmentActivity(Activity fromActivity) { fromActivity.finish(); } public static void closeToStartActivity(Activity fromActivity) { Intent i = new Intent(fromActivity, SomeStartActivity.class); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); fromActivity.startActivity(i); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_empty_container); // intentパラメータ優先 Bundle args = (getIntent() != null) ? getIntent().getExtras() : savedInstanceState; if (args == null) { throw new RuntimeException("Wrapper: Empty arguments"); } // 呼び出しFragment特定、初期化 String className = args.getString(ARGS_FRAGMENT); if (className == null || className.isEmpty()) { throw new RuntimeException("Wrapper: Empty class name"); } Fragment f = null; try { Class clazz = Class.forName(className); Method newInstance = clazz.getMethod("newInstance", Bundle.class); f = (Fragment)newInstance.invoke(null, args); replaceFragment(f); } catch (ClassNotFoundException e) { e.printStackTrace(); finish(); } catch (NoSuchMethodException e) { e.printStackTrace(); finish(); } catch (IllegalAccessException e) { e.printStackTrace(); finish(); } catch (IllegalArgumentException e) { e.printStackTrace(); finish(); } catch (InvocationTargetException e) { e.printStackTrace(); finish(); } } @Override public void onBackPressed() { if (getSupportFragmentManager().getBackStackEntryCount() == 1) { closeFragmentActivity(this); } else { super.onBackPressed(); } } public void replaceFragment(Fragment f) { getSupportFragmentManager() .beginTransaction() .addToBackStack(null) .replace(R.id.empty_container, f) .commit(); } }
2014年11月17日月曜日
AndroidでBlur effect
要はiOS7以降のBlur effectぽいことをしたい場合。
・android-stackblurを使う。
・RenderScriptはradiusがMAX25までしか設定できないぽいので期待しない。
・Eclipse想定
・stackblurをDLして、StackBlurディレクトリをプロジェクトimport。
・プロジェクトのコンテキストメニューから、Build Project
・libsディレクトリ配下にビルド成果物ができるので、まるっと開発プロジェクトのlibs配下にコピー
※stackblurのrenderscript8.jarでの競合が無ければIs Libraryでの追加でも大丈夫かも。
>そうするとDialogの位置とサイズが崩れる。styleで色々設定しても駄目。
>なのでAlertDialogは諦めて自前でCustomViewを作る必要がある。
>それも含めたベースのDialogFragment
/hoge/fuga/AbstractDialogFragment.java
/res/layout/dialog_base.xml
・Dialogを使う場合はAbstractDialogFragmentをextend。
・dialogの設定をするときはonCreateDialog()をoverrideしてsuper.onCreateDialog()してから設定。
・ViewはonCreateView()をoverrideして、super.onCreateView()してから子Viewを作り、super.addViewToContainer(childDialogView)する。
GPUImage for androidがblur effect対応してくれたら嬉しいな〜。
・android-stackblurを使う。
・RenderScriptはradiusがMAX25までしか設定できないぽいので期待しない。
・Eclipse想定
StackBlurライブラリの開発プロジェクトへのインストール
・NDK導入・stackblurをDLして、StackBlurディレクトリをプロジェクトimport。
・プロジェクトのコンテキストメニューから、Build Project
・libsディレクトリ配下にビルド成果物ができるので、まるっと開発プロジェクトのlibs配下にコピー
※stackblurのrenderscript8.jarでの競合が無ければIs Libraryでの追加でも大丈夫かも。
利用例
StackBlurManager _stackBlurManager = new StackBlurManager(orig); _stackBlurManager.processNatively(radius); Bitmap blurred = _stackBlurManager.returnBlurredImage();
利用例:Dialogで使う場合
Dialogに背景画像設定する場合は、DialogのWindow層に設定。>そうするとDialogの位置とサイズが崩れる。styleで色々設定しても駄目。
>なのでAlertDialogは諦めて自前でCustomViewを作る必要がある。
>それも含めたベースのDialogFragment
/hoge/fuga/AbstractDialogFragment.java
package hoge.fuga; import com.enrique.stackblur.StackBlurManager; import hoge.fuga.R; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.DialogInterface; import android.content.DialogInterface.OnShowListener; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.os.Build; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.FrameLayout; abstract public class AbstractDialogFragment extends DialogFragment implements OnShowListener { public static final String TAG = "AbstractDialogFragment"; protected Dialog mDialog; private ViewGroup mContainer; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { mDialog = super.onCreateDialog(savedInstanceState); // Get status bar height Rect rectgle= new Rect(); getActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(rectgle); int statusBarHeight = rectgle.top; // Screen shot http://stackoverflow.com/a/9596132/1121509 View v = getActivity().getWindow().getDecorView(); v.setDrawingCacheEnabled(true); Bitmap ss = v.getDrawingCache(); if (ss != null) { ss = Bitmap.createBitmap(ss, 0, statusBarHeight, ss.getWidth(), ss.getHeight() - statusBarHeight); } v.setDrawingCacheEnabled(false); // Blur effect if (ss != null) { int radius = (int) (ss.getHeight() * 0.25); radius = radius > 100 ? 100 : radius; StackBlurManager _stackBlurManager = new StackBlurManager(ss); _stackBlurManager.processNatively(radius); Bitmap blurred = _stackBlurManager.returnBlurredImage(); mDialog.getWindow().setBackgroundDrawable(new BitmapDrawable(getResources(), blurred)); } // without title mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // set listener mDialog.setOnShowListener(this); return mDialog; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // コンテナの設定 mContainer = (ViewGroup) inflater.inflate(R.layout.dialog_base, container, false); return mContainer; } public void addViewToContainer(View contentView) { ((ViewGroup) mContainer.findViewById(R.id.dialog_container)).addView(contentView, 0); } @SuppressLint("NewApi") @SuppressWarnings("deprecation") @Override public void onShow(DialogInterface dialog) { // サイズ調整、このタイミングでないとうまく動かない Point size = new Point(); Display display = getActivity().getWindowManager().getDefaultDisplay(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { display.getSize(size); } else { size.x = display.getWidth(); size.y = display.getHeight(); } FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)mContainer.getLayoutParams(); lp.width = size.x; lp.height = size.y; ViewGroup dialogContainer = (ViewGroup) mContainer.findViewById(R.id.dialog_container); FrameLayout.LayoutParams lp2 = (FrameLayout.LayoutParams) dialogContainer.getLayoutParams(); lp2.topMargin = (size.y - dialogContainer.getMeasuredHeight()) / 2; } }
/res/layout/dialog_base.xml
・Dialogを使う場合はAbstractDialogFragmentをextend。
・dialogの設定をするときはonCreateDialog()をoverrideしてsuper.onCreateDialog()してから設定。
・ViewはonCreateView()をoverrideして、super.onCreateView()してから子Viewを作り、super.addViewToContainer(childDialogView)する。
GPUImage for androidがblur effect対応してくれたら嬉しいな〜。
ElasticSearchのインストール
検索サーバElasticSearchのインストールと設定。AWS(EC2)での利用。2014.11.15現在。
http://stackoverflow.com/questions/25518908/issues-after-elasticsearch-1-3-2-upgrade
※kuromoji, cloud-awsはelasticsearchのバージョンに応じて入れるバージョンが変わる。それぞれ公式のsetup情報にバージョン対応表が載ってるので確認。上記は1.4.0の場合。
※host_typeはpublic_ipでも問題ないと思われる(未確認)
※ regionなしだと接続できずv2.4.0
ttp://ipaddar:9200/_plugin/HQ/
プラグインをインストールできてれば、上記でアクセス可能。
Multi masterは出来ないので複数台構成にしてもmasterサーバはひとつ。可用性を考えるなら、dataを持たないゲートウェイ的なマスタを作り、そこに子をぶら下げる形か。
trittonn, mroonga, Lucene, Solrと比べて検索システムの中ではだいぶ導入が容易な印象。運用考えると日本語対応した今はCloudSearch使ったほうが楽かも。ただElasticSearchからCloudSearchへのスイッチはサービス拡大に応じて行えるレベルかな。
1. Javaのバージョンを1.7.xにする
もし問題なければ飛ばす。単純アップデートだと古いのものこってて競合するそうなので、古いのはremoveするhttp://stackoverflow.com/questions/25518908/issues-after-elasticsearch-1-3-2-upgrade
# java -version # yum install java-1.7.0-openjdk # yum remove install openjdk-6-jre # yum remove java-1.6.0-openjdk
2. ElasticSearch本体及びプラグインのインストール
# rpm -ivh https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.0.noarch.rpm # /usr/share/elasticsearch/bin/plugin --install mobz/elasticsearch-head # /usr/share/elasticsearch/bin/plugin --install royrusso/elasticsearch-HQ # /usr/share/elasticsearch/bin/plugin --install elasticsearch/elasticsearch-analysis-kuromoji/2.4.1 # /usr/share/elasticsearch/bin/plugin --install elasticsearch/elasticsearch-cloud-aws/2.4.0※head, HQはおこのみで。
※kuromoji, cloud-awsはelasticsearchのバージョンに応じて入れるバージョンが変わる。それぞれ公式のsetup情報にバージョン対応表が載ってるので確認。上記は1.4.0の場合。
3. 設定ファイル
1台構成ならcluster.name位設定しとけばほかはいらない。EC2で複数台サーバを連携する場合は自動でネゴシエートするためのbroadcastが使えないので、cloud-awsプラグインを入れて設定を行う。また利用するEC2インスタンスはSecurity Groupで9200-9400のPortを開けておく。cluster.name: hoge # multi-server for EC2 settings discovery.zen.ping.multicast.enabled: false cloud.aws.access_key: XXXX cloud.aws.secret_key: XXXX cloud.aws.region: ap-northeast discovery.ec2.host_type: private_ip discovery.ec2.ping_timeout: 5s discovery.type: ec2 discovery.ec2.groups: IDorNAME※access_key, secret_keyはAWSのIAM Roleの設定で、EC2のDescribeの権限を付けたものを設定
※host_typeはpublic_ipでも問題ないと思われる(未確認)
※ regionなしだと接続できずv2.4.0
4. 起動
# chkconfig --add elasticsearch on # /etc/init.d/elasticsearch start
他
PHPのクライアントをComposerでインストール
$ php ../composer.phar require elasticsearch/elasticsearch:">=1.0"
HQ, headによる状態確認
ttp://ipaddar:9200/_plugin/head/ttp://ipaddar:9200/_plugin/HQ/
プラグインをインストールできてれば、上記でアクセス可能。
Multi masterは出来ないので複数台構成にしてもmasterサーバはひとつ。可用性を考えるなら、dataを持たないゲートウェイ的なマスタを作り、そこに子をぶら下げる形か。
trittonn, mroonga, Lucene, Solrと比べて検索システムの中ではだいぶ導入が容易な印象。運用考えると日本語対応した今はCloudSearch使ったほうが楽かも。ただElasticSearchからCloudSearchへのスイッチはサービス拡大に応じて行えるレベルかな。
CakePHP3の環境切り分け
CakePHP3でのdevelopment/productionなどの環境ごとの設定をどうするか。
公式ドキュメントを読むと、どうもbootstrapで設定を追加読み込みするよう促しているのでそれに倣う。
以下の設定で、基本は本番環境になり、developmentの環境変数を設定することで、開発環境の設定を上書きする形になる。
Apacheの場合は
公式ドキュメントを読むと、どうもbootstrapで設定を追加読み込みするよう促しているのでそれに倣う。
以下の設定で、基本は本番環境になり、developmentの環境変数を設定することで、開発環境の設定を上書きする形になる。
config/bootstrap.php
app.phpの読み込みをした後に、追加の設定を環境に応じて読み込む。config/app_development.phpに開発環境で上書きする設定を記述する。try { Configure::config('default', new PhpConfig()); Configure::load('app.php', 'default', false); // Add this 3 lines if (env("APPLICATION_ENV") == "dev" || env("APPLICATION_ENV") == "development") { Configure::load('app_development.php', 'default', true); } } catch (\Exception $e) { die('Unable to load config/app.php. Create it by copying config/app.default.php to config/app.php.'); }
Server setting
nginxの場合はvirtualhostなどserverの設定でphpに渡す環境変数を設定する。server { location ~ \.php$ { fastcgi_param APPLICATION_ENV development; } }
Apacheの場合は
SetEnv APPLICATION_ENV developmentかな。最近触ってないから忘れたけど。
2014年10月23日木曜日
ChromeでAjax(POST, PUT, DELETE)の実行テスト
1. 下記jsの2行目にHTTPMethod、URL、urlencoded形式のリクエストデータを追加
2. Chromeの開発者ツールのConsoleなどページでjs実行できる画面開いて以下実行。
(function(m,u,p){var x=new XMLHttpRequest();x.onreadystatechange=function(){if(x.readyState==4)console.log("res:"+x.responseText);};x.open(m,u);x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader('Content-Type','application/x-www-form-urlencoded');x.send(p)}) ("POST","http://example.jp/”, 'url=encoded¶meters=string');
2014年9月23日火曜日
CakePHP3.0でDBを使わずBasic認証
CakePHPのBasic認証はdb使わなくちゃいけなくて不便。そんなユーザ増やすわけでもないしソースに記述があれば十分。みたいな時に使う。
passワードの記述は適当なsalt混ぜてmd5とかでハッシュ化しとくとより良さそう。
passワードの記述は適当なsalt混ぜてmd5とかでハッシュ化しとくとより良さそう。
代替クラス
# src/Auth/BasicwodbAuthenticate.php$p) { if ($username === $u && $password === $p) { return array('username' => $username); } } return false; } }
設定
# src/config/app.phpreturn [ 'App' => [ 'Basicwodb' => ['some-username' => 'some-pass'], ], ];
CakePHP3.0でURLを小文字でもControllerにつなぐ
config/routes.phpでオプション設定する。”['routeClass' => 'InflectedRoute']”を追加すると小文字のコントローラ名をinflectしてくれる。
connect('/', ['controller' => 'Index', 'action' => 'index']); // $routes->connect('/:controller/:action/*'); $routes->connect('/', ['controller' => 'Index', 'action' => 'index'], ['routeClass' => 'InflectedRoute']); $routes->connect('/:controller/:action/*', [], ['routeClass' => 'InflectedRoute']);
2014年6月28日土曜日
Androidでpinch in/outのjsイベント(gesturestart, gesturechange, gestureend)
gesturestart, gesturechange, gestureendはAndroidに無いので、独自実装。
var funcGestureStart = function (e) {}; var funcGestureChange = function (e) {}; var funcGestureEnd = function (e) {}; // iOS向けイベント設定 document.body.addEventListener('gesturestart', funcGestureStart, false); document.body.addEventListener('gesturechange', funcGestureChange, false); document.body.addEventListener('gestureend', funcGestureChange, false); // Android向けイベント設定 var pinchDistance = 0; document.body.addEventListener('touchstart',function(e){ if(e.touches.length > 1){ pinchDistance = Math.sqrt(Math.pow((e.touches[1].pageX - e.touches[0].pageX),2)+Math.pow((e.touches[1].pageY - e.touches[0].pageY),2)); funcGestureStart(e); } else { pinchDistance = 0; } },false); document.body.addEventListener('touchmove', function (e) { if (pinchDistance <= 0) { return; } var newDistance = Math.sqrt(Math.pow((e.touches[1].pageX - e.touches[0].pageX),2)+Math.pow((e.touches[1].pageY - e.touches[0].pageY),2)); var event = {scale: newDistance / pinchDistance}; funcGestureChange(event); }); document.body.addEventListener('touchmove', function (e) { if (pinchDistance <= 0) { return; } funcGestureEnd(e); });
2014年6月16日月曜日
Yii2のインストール
パッケージ管理システムのcomposerを使って、yii2を入れる。phpはインストール前提(v5.4以上)
composerでは、composer.jsonが設定、composer.lockが現在の状態データ、composer.pharが実行データになる。
実際にリポジトリで管理するのは上記の3ファイルのみ。他はwebサーバ立ち上げてリポジトリからデプロイした後に、php composer.phar install とか php composer.phar update とかバージョン古くなってるて警告出たら php composer.phar self-update とか便宜実行。
どうでもいいけど、composerっていつもcomporserとtypoしてしまう。打ちづらい。
参考:http://www.yiiframework.com/doc-2.0/
Composerのインストール、初期化
## プロジェクトのディレクトリを作る $ mkdir -p /path/to/project $ cd $_ ## composerインストール $ curl -sS https://getcomposer.org/installer | php ## composerの初期化 (201406現在yii2はbetaのため、stabilityにdevを設定) $ php composer.phar init -name vendername/projectname -author authorName –stablility devこれで、カレントディレクトリに「composer.phar」「composer.json」が出来る。
Yii2のインストール
$ php composer.phar require --prefer-dist "yiisoft/yii2 *" ## yiiプロジェクトのセットアップ $ php composer.phar create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic /path/to/projectこれで、カレントディレクトリに「vendor」ディレクトリと管理されているパッケージ、「composer.lock」が出来る。
composerでは、composer.jsonが設定、composer.lockが現在の状態データ、composer.pharが実行データになる。
実際にリポジトリで管理するのは上記の3ファイルのみ。他はwebサーバ立ち上げてリポジトリからデプロイした後に、php composer.phar install とか php composer.phar update とかバージョン古くなってるて警告出たら php composer.phar self-update とか便宜実行。
どうでもいいけど、composerっていつもcomporserとtypoしてしまう。打ちづらい。
参考:http://www.yiiframework.com/doc-2.0/
2014年5月22日木曜日
PHPのバックトレースを程よい文字列で取得
バックトレースを文字列で欲しい場合。
・debug_print_backtrace()では出力してしまうのでoutput bufferなどでの補足が必要で微妙。
・debug_backtrace(); は配列なので冗長。。もっとコンパクトにまとまってて欲しい。
と思ってたんだけど、PHPマニュアルのコメント欄でいいものを見つけた。
これくらいの出力がちょうどいい。
・debug_print_backtrace()では出力してしまうのでoutput bufferなどでの補足が必要で微妙。
・debug_backtrace(); は配列なので冗長。。もっとコンパクトにまとまってて欲しい。
と思ってたんだけど、PHPマニュアルのコメント欄でいいものを見つけた。
$e = new Exception(); print_r(str_replace('/path/to/code/', '', $e->getTraceAsString()));from http://www.php.net/manual/ja/function.debug-print-backtrace.php#92542
これくらいの出力がちょうどいい。
2014年5月1日木曜日
PHP, ImagickでNeon系装飾で文字を入れる
Neonというか覆い焼き
例:
ポイントは
・Imagick::blurImage()で適度にぼかす
・Imagick::compositeImage()でImagick::COMPOSITE_COLORDODGE(覆い焼き)をする
単に一度だけの合成だとネオン効果が弱い気がするのでぼかし下地で強化。
例:
$TEXT = "example example!"; $FONT_SIZE = 32; $FWCOLOR = "#FFFFFF"; $BGCOLOR = "#FF0000"; // 貼り付け先の画像 $im = new Imagick(); $im->readImageBlob(file_get_contents('/path/to/baseimagefile')); // 文字入れ作業用の画像 $tmp = new Imagick(); $tmp->newImage($im->getImageWidth(), $im->getImageHeight(), "transparent", "png"); $tmp2 = clone $tmp; // 文字入れ用の設定 $draw = new ImagickDraw(); //$draw->setFont('/path/to/font/file'); $draw->setFontSize($FONT_SIZE); $draw->setGravity(Imagick::GRAVITY_CENTER); // 文字:ぼかし下地 $draw->setFillColor($BGCOLOR); $tmp->annotateImage($draw, 0, 0, 0, $TEXT); $tmp->blurImage($FONT_SIZE / 8, $FONT_SIZE / 10, Imagick::CHANNEL_ALL); // 文字:全面に来る文字部分 $draw->setFillColor($FWCOLOR); $tmp->annotateImage($draw, 0, 0, 0, $TEXT); // 文字:ぼかし調整 $draw->setFillColor($BGCOLOR); $tmp2->annotateImage($draw, 0, 0, 0, $TEXT); $tmp2->blurImage(5, 3, Imagick::CHANNEL_ALL); $tmp->compositeImage($tmp2, Imagick::COMPOSITE_COLORDODGE, 0, 0); // 最終画像結合 $im->compositeImage($tmp, Imagick::COMPOSITE_COLORDODGE, 0, 0); // 出力 //$output = $im->getImagesBlob(); //header('Content-Type: ' . $im->getimagemimetype()); //echo $output;
ポイントは
・Imagick::blurImage()で適度にぼかす
・Imagick::compositeImage()でImagick::COMPOSITE_COLORDODGE(覆い焼き)をする
単に一度だけの合成だとネオン効果が弱い気がするのでぼかし下地で強化。
2014年4月30日水曜日
UIWebViewへアプリ作成画像(UIImage)を入れ込む
AssetLibraryを使わず、画像などをData URI Schemeでhtmlに直接埋め込む。
jsの変数に入れて使ったりも出来る。その場合は"data:image/[format];base64,[content]"をさらにJSONエンコードしとかないと動かないかも。
- (void)changeImage:(UIImage*)image webview:(UIWebView*)webview imageDomId:(NSString*)domId { NSData *imageData = UIImageJPEGRepresentation(image, 0.8f); // iOS7以上、6以下は何かライブラリ使う NSString *imageBase64 = [imageData base64EncodedStringWithOptions:0]; // encodedに改行が含まれてるとuiwebviewでエラーになるため、取り除く // 上記encodeメソッドで改行が含まれないのであれば不要 imageBase64 = [imageBase64 stringByReplacingOccurrencesOfString:@"\r" withString:@""]; imageBase64 = [imageBase64 stringByReplacingOccurrencesOfString:@"\n" withString:@""]; [webview stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"$('%@').attr('src', 'data:image/jpeg;base64,%@');", domId, imageBase64]; }
jsの変数に入れて使ったりも出来る。その場合は"data:image/[format];base64,[content]"をさらにJSONエンコードしとかないと動かないかも。
2014年3月25日火曜日
2014年、PHPフレームワーク雑感(CakePHP, FuelPHP, Yii, ZendFramework)
まとめると、中規模開発以上はYii、ミニサービスやスモールスタートならCakePHPが良いかなと思う。
CakePHPが良いのはやはり学習コストが低い点。お膳立てが多いので欲しいなと思ったものはだいたいある。まだ安定版出てないけどこれからは3.xでいいと思う。
個人的に気になったところは、
・autoload:ディレクトリパス指定とかで自動で読み込んで欲しい。
・ORM:2.xでは推奨されておらず謎のストレスフルな配列結果セットを使うことになる。3.xでは改善されそう。
・マジックメソッド多用:コード補完が効かなくてつらい。
SELECTもController側でmodel->select()->where()みたいなことせずに、それぞれ該当モデルにてメソッド化する方が後から見た時にわかりやすい。
各FWともPSRとか出てきてここ2年くらいで刷新したバージョンを出してる(出そうとしてる)けど、その中だとやはりCakePHP-3.xとYii-2.x系が良さそうだなと思う。
他のフレームワークで注視しとくのはLaravelくらいか。
CakePHPが良いのはやはり学習コストが低い点。お膳立てが多いので欲しいなと思ったものはだいたいある。まだ安定版出てないけどこれからは3.xでいいと思う。
CakePHP(2.x)
公式ドキュメントを参照するだけでほとんど迷うこと無く開発を進めることが出来る。導入のしやすさはピカイチ。ただし細かいことしようとするとブラックボックスな配列の取り回しに苦労する。とにかく配列が深い、引数が多い、謎、ストレス。個人的に気になったところは、
・autoload:ディレクトリパス指定とかで自動で読み込んで欲しい。
・ORM:2.xでは推奨されておらず謎のストレスフルな配列結果セットを使うことになる。3.xでは改善されそう。
・マジックメソッド多用:コード補完が効かなくてつらい。
FuelPHP(1.x)
CakePHPに比べてお膳立てが少ないので自分であれこれ付け加える必要がある。ディレクトリ構成がモヤッとする。fuel/app/classesとか。導入はCakePHPについで楽だしFuelとかoilとかforgeとかなんかかっこいいけど、CakePHPを超えるメリットはあらかじめ環境切り分け(Production, Develop / DB master, slave)が考慮されているところくらいしか思いつかなかった。ORMのテーブル情報をキャッシュしてくれないところも微妙な点。Yii(1.1.x)
日本では人気無いけど英語圏では人気のFWなので情報が豊富。ディレクトリ構成がわかりやすくて、Viewのコンポーネントも充実してる。CakeやFuelよりは導入コストがかかるが、Zendよりは導入しやすい。Zend(2.x)
1.xから大きく変わり、色々煩雑になってしまった印象。全体的にお固くて設定の配列が冗長、ディレクトリ構造もわかりづらい。FW自体開発者の利便性よりもオブジェクト指向優先でクラスは細かく細分化されている。学習コストは高いが、その分一度慣れると収まるものが収まるところに収まってるので使いやすく感じる。Zend_Formはとても良い。まとめ2
ORMは信用しない方が良い。単純な取得や単体での保存では使うが、複雑な条件での取得・トランザクションはモデル内のメソッドとして自前で実装したほうが良い。特にリレーション設定(hasOne, hasMany等)は使わない。SELECTもController側でmodel->select()->where()みたいなことせずに、それぞれ該当モデルにてメソッド化する方が後から見た時にわかりやすい。
他のフレームワークで注視しとくのはLaravelくらいか。
登録:
投稿 (Atom)