トップ 最新 追記

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|

2013-06-09 [Android]アクティビティの表示

iOSアプリケーションは伝統的なUnixアプリケーションだが、Androidは独特だ。

アクティビティを簡単に説明すると画面という事になるのだが、システムのアクティビティマネージャによって開かれた画面はスタック構造で管理され、WebブラウザのBackボタンのように、前のアクティビティに戻る動きをする。
Linuxのプロセスとアプリケーションのライフサイクルは等号でなく、プロセスはアクティビティを入れる容器にすぎない。

アクティビティには、launchModeという開かれた際の挙動を定義する項目があり、これには以下の4つの種類がある。

LaunchModeandroid:launchMode起動タスクインスタンス化
standardmultiple呼び出し元タスク追加
singleTopsingleTop呼び出し元タスク対象アクティビティが最上位でない場合は追加。その他は再利用。
singleTasksingleTask新規タスク既存インスタンスの再利用。
singleInstancesingleInstance新規タスク追加

アクティビティが呼び出し元タスクに属する事に驚いたが、同一アプリケーション内部の場合に限定すると、あるアクティビティを開くインテントを実行した際に、とにかく開く要求が発生したら、その度に、ある画面を出したい場合はstandardを、そのアクティビティが開かれていた場合は新規に画面を開きたくない場合は、simgleTopをというのが良さそうだ。

実は、あるアプリケーションを作っていて、それはアプリ内のサービスから、通知経由で、そのアプリをフロントに移動させるという動きをさせたいのだが、フロントに移動する度にアクティビティが追加されて困っていた為、調査していた。

この問題そのものについて、Android関連のMLで答えを教えてもらったので、それも紹介しよう。

同一アプリで、あるアクティビティを開く場合は、以下のようにインテントを記述すると思うが、

Intent intent = new Intent(this, アクティビティ名.class);
startActivity(intent);

この時に以下の設定を追加すればいい。

intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);

質問の場を設けてくれた日本Androidの会の皆さん、ありがとうございます。助かりました!

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

2013-06-16 [Android]タイトルバーの背景色

Androidで、テーマとして「Theme.Light」を使用している場合、タイトルバーの背景色を変更するには、どうすればいいか?

res/values/colors.xmlに指定したい色を定義する。

<resources>
    <color name="custom_theme_color">#FFFFFF00</color>
</resources>

res/values/styles.xmlに、独自のテーマを定義する。

<resources>
    <style name="MyFirstAppTheme" parent="android:Theme.Light">
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowTitleBackgroundStyle">@style/WindowTitleBackground
</resources>

windowContentOverlayはタイトルバーンの影で非表示にした。

AndroidManifest.xmlで、定義してテーマを背景色を変更したいアクティビティに設定する。

        <activity
            android:name="demo.myfirstapp.MainActivity"
            android:label="@string/app_name"
            android:theme="@style/MyFirstAppTheme" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

この例では、タイトルバーの背景色は黄色になる。

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

2013-06-17 [Android]ネット上の画像の全画面表示

AndroidManifest.xmlで、通信の利用を有効にする。

<uses-permission android:name="android.permission.INTERNET" />

例では、主アクティビティで、画像を一個、表示するようにしている。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
	
    <ImageView
        android:id="@+id/imageview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitStart" />
	
</RelativeLayout>

activity_vertical_marginとactivity_horizontal_marginは0に設定している。scaleTypeはfitStartを指定しているので、画面上部に表示される。

AsyncTaskを使って、画像をダンロードして、表示した。

public class MainActivity extends Activity {
	private	ImageView	imageView = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		imageView = (ImageView)findViewById(R.id.imageview);
		new DownloadImageTask().execute("画像のURL");
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	private class DownloadImageTask extends AsyncTask {
		private static final String TAG = "DownloadImageTask";
		
		@Override
		protected Bitmap doInBackground(String ... urlString) {
			Bitmap bitmap = null;
		    try {
		        URL url = new URL(urlString[0]);
		        URLConnection urlConnection = url.openConnection();
		        urlConnection.connect();
		        InputStream is = urlConnection.getInputStream();
		        BufferedInputStream bis = new BufferedInputStream(is);
		        bitmap = BitmapFactory.decodeStream(bis);
		        bis.close();
		        is.close();
		    } catch (IOException e) {
		        Log.e(TAG,"Error getting the image from server : " + e.getMessage().toString());
		    } 
		    return bitmap;
		}
		
		@Override
		protected void onPostExecute(Bitmap bitmap) {
			imageView.setImageBitmap(bitmap);
		}
	}
}

どうしても、気持ち悪いので、インスタンスの初期値としてnullを設定してしまう。

AsyncTaskは、全体で一度に一個の処理しか実行しないので、何でもかんでもAsyncTaskで非同期処理すると、著者のように困った事象に遭遇してしまうので気をつけた方がいい。

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

2013-06-23 [OSX]ドライバについて(kext)

Apple開発者のサイトでDarwinのソースコードが公開されているが、ドライバ関連では、文書とサンプルコードも付属しているので、開発したいものに近いサンプルコードを基に拡張していく方法もあるが、今回は、Xcodeの新規プロジェクトから製作してみようと思う。

Xcodeでドライバの新規プロジェクトを生成する場合、雛形としては、Generic Kernel ExtensionとIOKit Driverの二種類があるが、その違いについてまとめてみる。

Generic kernel extension templateIOKit driver template
開発言語CEmbedded C++
実装方法コールバック関数I/O Kitクラスの派生クラス
実行方法明示的に起動と停止自動

それでは、kext(generic kernel extension)を作ってみよう。

新規プロジェクトで、Generic kernel extension templateを選択する。

新規プロジェクトkext

プロジェクト名は、Smart Scrollという製品に対するプログラムを作成しようと思ったので、サンプルでは、SmartScrollKextとした。

TARGETSのArchitecturesのBuild Active Architecture Onlyは、NOを選択する。これを設定しておかないと、32bitカーネルで動作している開発機で、64bitドライバを生成し、テストに失敗してしまうなどのトラブルに遭遇する可能性がある。

アーキテクチャ

SmartScrollKext.cにデバッグ出力を追加する。

#include <sys/systm.h>
#include <mach/mach_types.h>
 
kern_return_t SmartScrollKext_start(kmod_info_t * ki, void *d);
kern_return_t SmartScrollKext_stop(kmod_info_t *ki, void *d);
 
kern_return_t SmartScrollKext_start(kmod_info_t * ki, void *d)
{
    printf("SmartScrollKext has started.\n");
    return KERN_SUCCESS;
}
 
kern_return_t SmartScrollKext_stop(kmod_info_t *ki, void *d)
{
    printf("SmartScrollKext has stopped.\n");
    return KERN_SUCCESS;
}

SmartScrollKext-Info.plistのCFBundleIdentifierをcom.MyCompany.kext.${PRODUCT_NAME:rfc1034identifier}に変更する。下記の例では、MyCompanyは著者の会社のものにしている。

CFBundleIdentifier

一度、プロジェクトをビルドする。Show the Log NavigatorからSmartScrollKext.kextの出力先を調べて、ターミナル.appで、そのディレクトリに移動する。

cd Build/Products/Debug

そこで以下のコマンドを実行する。

$ kextlibs -xml SmartScrollKext.kext
	<key>OSBundleLibraries</key>
	<dict>
		<key>com.apple.kpi.libkern</key>
		<string>11.4.2</string>
	</dict>

この内容をSmartScrollKext-Info.plistのOSBundleLibrariesに設定する。

OSBundleLibraries

再度、ビルドし、生成されたSmartScrollKext.kextを/tmpにコピーする。

$ sudo cp -R SmartScrollKext.kext /tmp

以下のコマンドで、問題がないか確認する。

$ kextutil -n -print-diagnostics /tmp/SmartScrollKext.kext
No kernel file specified; using running kernel for linking.
/tmp/SmartScrollKext.kext appears to be loadable (including linkage for on-disk libraries).

ログ確認の準備を行う。

$ cd /var/log
$ tail -f kernel.log

ロードする。

$ sudo kextload /tmp/SmartScrollKext.kext

アンロードする。

$ sudo kextunload /tmp/SmartScrollKext.kext

ログにデバッグ出力が印字されている事を確認する。

Jun 24 00:31:39 マシン名 kernel[0]: SmartScrollKext has started.
Jun 24 00:33:08 マシン名 kernel[0]: SmartScrollKext has stopped.

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

2013-06-30 [OSX]ドライバについて(driver)

今回は、IOKit driver templateで生成したプロジェクトを使って開発だ。

新規プロジェクトで、IOKit driver templateを選択する。

新規プロジェクトdriver

プロジェクト名は、前回の流れからSmartScrollDriverとした。

今回も、前回と同様にTARGETSのArchitecturesのBuild Active Architecture Onlyは、NOを選択する。

SmartScrollDriver-Info.plistのCFBundleIdentifierをcom.MyCompany.driver.${PRODUCT_NAME:rfc1034identifier}に変更する。著者は、MyCompanyに自分の会社のものにしている。

SmartScrollDriver-Info.plistのIOKitPersonalitiesにSmartScrollDriver辞書型を追加して、以下の内容に設定する。

NameValue
CFBundleIdentifiercom.MyCompany.driver.${PRODUCT_NAME:rfc1034identifier}
IOClasscom_MyCompany_driver_SmartScrollDriver
IOKitDebug65535
IOProviderClassIOResources
IOMatchCategorycom_MyCompany_driver_SmartScrollDriver
IOKitPersonalities

IOClassは、このドライバの起点となるクラス名の様だ。ようするに、この名前のクラスを実装する事になる。

IOProviderClassは、ドライバがぶら下がるnubクラス名。

テンプレートのSmartScrollDriver.hとSmartScrollDriver.cppは空なので中身を実装する。メソッドが呼ばれたらにデバッグ出力するだけだ。

#include <IOKit/IOService.h>
class jp_co_bitz_driver_SmartScrollDriver : public IOService {
    OSDeclareDefaultStructors(jp_co_bitz_driver_SmartScrollDriver)
public:
    virtual bool init(OSDictionary *dictionary = 0);
    virtual void free(void);
    virtual IOService *probe(IOService *provider, SInt32 *score);
    virtual bool start(IOService *provider);
    virtual void stop(IOService *provider);
};
#include <IOKit/IOLib.h>
#include "SmartScrollDriver.h"
 
OSDefineMetaClassAndStructors(jp_co_bitz_driver_SmartScrollDriver, IOService)
 
#define super IOService
 
bool jp_co_bitz_driver_SmartScrollDriver::init(OSDictionary *dict)
{
    bool result = super::init(dict);
    IOLog("Initializing\n");
    return result;
}
 
void jp_co_bitz_driver_SmartScrollDriver::free(void)
{
    IOLog("Freeing\n");
    super::free();
}
 
IOService *jp_co_bitz_driver_SmartScrollDriver::probe(IOService *provider,
                                                SInt32 *score)
{
    IOService *result = super::probe(provider, score);
    IOLog("Probing\n");
    return result;
}
 
bool jp_co_bitz_driver_SmartScrollDriver::start(IOService *provider)
{
    bool result = super::start(provider);
    IOLog("Starting\n");
    return result;
}
 
void jp_co_bitz_driver_SmartScrollDriver::stop(IOService *provider)
{
    IOLog("Stopping\n");
    super::stop(provider);
}

一度、プロジェクトをビルドする。Show the Log NavigatorからSmartScrollDriver.kextの出力先を調べて、ターミナル.appで、そのディレクトリに移動する。

cd Build/Products/Debug

そこで以下のコマンドを実行する。

$ kextlibs -xml SmartScrollDriver.kext
	<key>OSBundleLibraries</key>
	<dict>
		<key>com.apple.kpi.iokit</key>
		<string>11.4.2</string>
		<key>com.apple.kpi.libkern</key>
		<string>11.4.2</string>
	</dict>

この内容をSmartScrollKext-Info.plistのOSBundleLibrariesに設定する。

再度、ビルドし、生成されたSmartScrollDriver.kextを/tmpにコピーする。

$ sudo cp -R SmartScrollDriver.kext /tmp

以下のコマンドで、問題がないか確認する。

$ kextutil -n -t /tmp/SmartScrollDriver.kext
No kernel file specified; using running kernel for linking.
Notice: /tmp/SmartScrollDriver.kext has debug properties set.
/tmp/SmartScrollDriver.kext appears to be loadable (including linkage for on-disk libraries).

ロードしてみる。

$ sudo kextutil -v /tmp/SmartScrollDriver.kext
Password:
Notice: /tmp/SmartScrollDriver.kext has debug properties set.
/tmp/SmartScrollDriver.kext appears to be loadable (not including linkage for on-disk libraries).
Loading /tmp/SmartScrollDriver.kext.
/tmp/SmartScrollDriver.kext successfully loaded (or already loaded).

確認する。

$ kextstat | grep jp.co.bitz
  162    0 0xb97000   0x4000     0x3000     jp.co.bitz.driver.SmartScrollDriver (1) <4 3>

アンロード。

$ sudo kextunload -v /tmp/SmartScrollDriver.kext
jp.co.bitz.driver.SmartScrollDriver unloaded and personalities removed.

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

トップ 最新 追記