トップ 最新 追記

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|

2014-09-07 [OSX][iOS][Android]cocos2d-xをインストールする

著者の場合、OS XとiOS、Androidでの開発を考えているので、事前に以下をインストールしておいた。

著者は、NDKを"/Applications/Android/NDK/android-ndk-r10"に配置した。このパスを.bash_profileに追加した。

NDKはバージョンアップされるたびにモノが公開され、モノ毎にディレクトリ名が異なるようだ。NDKのパスをcocos2d-xに設定する為、"android-ndk-r10"を"android-ndk"に名前を変えて、"/Applications/Android"直下に置くことも考えたが、今回はこのようにした。

$ cat .bash_profile
export PATH=$PATH:/Applications/Android/NDK/android-ndk-r10

そして、cocos2d-xを入手する。

cocos2d-xの置き場所だが、著者は"/Users/yukio/Documents/Development/cocos2d-x-3.2"に置いた。

次に、cocos2d-xの設定だ。

$ cd /Users/yukio/Documents/Development/cocos2d-x-3.2
$ python download-deps.py
$ ./setup.py
$ source ~/.bash_profile

Android SDKとNDKのパスが聞かれると思うので、さっき、配置したパスを入力する。

新規プロジェクトを作ってみる。

$ cd ~/Documents/Development
$ cocos new MyGame -p jp.co.bitz.mygame -l cpp -d Projects

OS XとiOSは、これでプロジェクトファイルが出来ているので、直に試せるが、Androidはまだまだ設定があるが、それはまたの機会に。

_ 【Cocoa練習帳】

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

2014-09-22 [Android]マルチスクリーンに対応する

iOSのiPhoneとiPadの両方に対応したMaster-DetailアプリケーションのAndroid版だ。

サンプルのアプリケーション名は、WebViewを使ったアプリケーションということでNeXTSTEP上で開発された世界で最初のWebブラウザと同じ名前にした。

AndroidManifest.xmlでは、WebViewを使うので通信を有効にするのと、スマートフォンの画面サイズでは、詳細画面でWebViewを表示するので詳細画面アクティビティを宣言する。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.nexus"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />
    
    <uses-permission android:name="android.permission.INTERNET"/>
 
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".DetailActivity" />
    </application>
 
</manifest>

スマートフォンとタブレットの画面サイズで、主アクティビティの表示内容を変えるため、主アクティビティのXMLファイルは、res/layoutとres/layout-largeの二種類を用意する。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	android:id="@+id/parent"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:orientation="vertical" >
 
	<fragment
		android:id="@+id/masterFragment"
		android:name="com.example.nexus.MasterFragment"
		android:layout_width="match_parent"
		android:layout_height="match_parent" />
	
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    
	<fragment
		android:id="@+id/masterFragment"
		android:tag="masterFragment"
		android:name="com.example.nexus.MasterFragment"
		android:layout_width="0dp"
		android:layout_height="match_parent"
		android:layout_weight="1.0" />
	
	<FrameLayout
	    android:id="@+id/detailPane"
	    android:layout_width="0dp"
		android:layout_height="match_parent"
		android:layout_weight="2.0" />
    
</LinearLayout>

主アクティビティでは、画面サイズの判定結果をメンバ変数で保持する。

package com.example.nexus;
 
import android.support.v7.app.ActionBarActivity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
 
public class MainActivity extends ActionBarActivity {
	static boolean isLargeScreen = false;
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		isLargeScreen = isLargeScreen();
	}
 
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
 
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
 
	public boolean isLargeScreen() {
		int layout = getResources().getConfiguration().screenLayout;
		return (layout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE; 
	}
}

一覧のXMLファイル。表示するサイト毎にボタンを用意。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Index"
        android:textSize="50sp"
         />
	<Button
	    android:id="@+id/button_google"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Google"
	    />
	<Button
	    android:id="@+id/button_bing"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bing"
	    />
	
</LinearLayout>

一覧のフラグメントのソースコード。画面サイズ毎に処理を分けている。

package com.example.nexus;
 
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
 
@SuppressLint("NewApi")
public class MasterFragment extends Fragment implements OnClickListener {
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		return inflater.inflate(R.layout.fragment_master, container, false);
	}
	
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		
		Button mButtonGoogle = (Button) getActivity().findViewById(R.id.button_google);
		mButtonGoogle.setOnClickListener(this);
 
		Button mButtonBing = (Button) getActivity().findViewById(R.id.button_bing);
		mButtonBing.setOnClickListener(this);
	}
	
	public void onClick(View v) {
		if (MainActivity.isLargeScreen) {
			FragmentTransaction transaction = getFragmentManager().beginTransaction();
			DetailFragment detailFragment = new DetailFragment();
			Bundle args = new Bundle();
			
			switch (v.getId()) {
				case R.id.button_google:
					args.putString("URL", "http://www.google.com/");
					break;
				case R.id.button_bing:
					args.putString("URL", "http://bing.com/");
					break;
			}
			detailFragment.setArguments(args);
			transaction.replace(R.id.detailPane, detailFragment);
			
			transaction.addToBackStack(null);
			
			transaction.commit();
		}
		else {
			Intent intent;
			switch (v.getId()) {
				case R.id.button_google:
					intent = new Intent(getActivity(), DetailActivity.class);
					intent.putExtra("URL",  "http://www.google.com/");
		            getActivity().startActivity(intent);
		            break;
				case R.id.button_bing:
					intent = new Intent(getActivity(), DetailActivity.class);
					intent.putExtra("URL",  "http://bing.com/");
		            getActivity().startActivity(intent);
					break;
			}
		}
	}
}

WebViewを配置して詳細画面のXMLファイル。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    
	<WebView 
	    android:id="@+id/detailWebView"
	    android:layout_width="match_parent"
	    android:layout_height="match_parent" />
</LinearLayout>

詳細画面のフラグメント。

package com.example.nexus;
 
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 
public class DetailFragment extends Fragment {
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saveInstanceState) {
		super.onCreateView(inflater, container, saveInstanceState);
		View view = inflater.inflate(R.layout.fragment_detail,  container, false);
		
		WebView webView = (WebView)view.findViewById(R.id.detailWebView);
		webView.setWebViewClient(new WebViewClient());
		String url = getArguments().getString("URL");
		webView.loadUrl(url);
		return view;
	}
}

詳細画面のアクティビティ版のXMLファイル。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    
    <WebView 
	    android:id="@+id/detailWebView"
	    android:layout_width="match_parent"
	    android:layout_height="match_parent" />
 
</LinearLayout>

対応するソースコード。

package com.example.nexus;
 
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 
public class DetailActivity extends Activity {
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        
        WebView webView = (WebView)findViewById(R.id.detailWebView);
        webView.setWebViewClient(new WebViewClient());
        String url = getIntent().getStringExtra("URL");
		webView.loadUrl(url);
    }
}

エミュレータの調子が悪いため、画面ダンプがとれなかった。残念。

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/android/Nexus - GitHub

_ 【Cocoa練習帳】

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

2014-09-24 [OSX][iOS][Android]cocos2d-xのAndroid環境を整える

前回のインストールの経験からAndroid環境を見直した。

ApplicationsディレクトリにDevelopmentディレクトリを用意して、そこにcocos2d-xとAndroid関連のツールを配置する事にした。

$ cd /Applications/Development
$ pwd
/Applications/Development
$ ls -l
lrwxr-xr-x  adt-bundle-mac-x86_64 -> adt-bundle-mac-x86_64-20140702
drwxrwxrwx@ adt-bundle-mac-x86_64-20140702
lrwxr-xr-x  android-ndk -> android-ndk-r10b
drwxr-xr-x@ android-ndk-r10b
lrwxr-xr-x  apache-ant -> apache-ant-1.9.4
drwxr-xr-x@ apache-ant-1.9.4
lrwxr-xr-x  cocos2d-x -> cocos2d-x-3.3beta0
drwxr-xr-x@ cocos2d-x-3.3beta0

Apache ANTはhttp://ant.apache.org/bindownload.cgiから入手した。

バージョンが変わる度に設定を変更するのは大変だが、ディレクトリ名を変更してしまうとバージョンが分からなくなるのでシンボリックリンクを作成した。

そして、cocos2d-xの設定を実行する。

$ cd /Applications/Development/cocos2d-x
$ ./setup.py
$ source ~/.bash_profile

Android NDKとSDK、APache ANTのパスが聞かれるはずで、著者の場合は以下を入力した。

    ->Added NDK_ROOT=/Applications/Development/android-ndk
    ->Added ANDROID_SDK_ROOT=/Applications/Development/adt-bundle-mac-x86_64/sdk
    ->Added ANT_ROOT=/Applications/Development/apache-ant/bin

すると、.bash_profileの内容は、以下の感じになるはずだ。

$ cd
$ cat .bash_profile
PATH="$PATH:~/bin"
 
# Add environment variable COCOS_CONSOLE_ROOT for cocos2d-x
export COCOS_CONSOLE_ROOT=/Applications/Development/cocos2d-x-3.3beta0/tools/cocos2d-console/bin
export PATH=$COCOS_CONSOLE_ROOT:$PATH
 
# Add environment variable NDK_ROOT for cocos2d-x
export NDK_ROOT=/Applications/Development/android-ndk
export PATH=$NDK_ROOT:$PATH
 
# Add environment variable ANDROID_SDK_ROOT for cocos2d-x
export ANDROID_SDK_ROOT=/Applications/Development/adt-bundle-mac-x86_64/sdk
export PATH=$ANDROID_SDK_ROOT:$PATH
export PATH=$ANDROID_SDK_ROOT/tools:$ANDROID_SDK_ROOT/platform-tools:$PATH
 
# Add environment variable ANT_ROOT for cocos2d-x
export ANT_ROOT=/Applications/Development/apache-ant/bin
export PATH=$ANT_ROOT:$PATH

これで準備ができたはずなので、前回同様、プロジェクトを作成してみよう。

$ cd ~/Documents/Development
$ cocos new MyGame -p jp.co.bitz.mygame -l cpp -d Projects

Androidのビルドを試してみよう。

$ cd Projects/MyGame/proj.android
$ ./build_native.py
Couldn't find the gcc toolchain.

あれ?失敗する。

気を取り直して、このプロジェクトをExclipseでimportしてみよう。

すると多数のプロジェクトが候補として現れるが、libcocos2dxと、今回生成したMyGameのみを選んで、後のチェックは外す。

ビルドしてみる。

[2014-09-24 22:45:17 - Dex Loader] Unable to execute dex: Multiple dex files define Lorg/cocos2dx/lib/Cocos2dxAccelerometer;
[2014-09-24 22:45:17 - MyGame] Conversion to Dalvik format failed: Unable to execute dex: Multiple dex files define Lorg/cocos2dx/lib/Cocos2dxAccelerometer;

あれ、失敗した。もしかしたら、NDKのバージョンが問題?

_ 【Cocoa練習帳】

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