728x90

aaplus-pc-tiles.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc 
		http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context.xsd">
	

	<bean id="templateResolver"
		class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
		<property name="prefix" value="/WEB-INF/view/" />
		<property name="suffix" value=".html" />
		<property name="templateMode" value="HTML5" />
		<property name="cacheable" value="true" />
	</bean>
	<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
		<property name="templateResolver" ref="templateResolver" />
	</bean>
	<bean class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
		<property name="templateEngine" ref="templateEngine" />
		<property name="order" value="1" />
		<property name="viewNames" value="thymeleaf/*" />
	</bean>

	<!-- Resolves view names to Tiles definitions -->
	<beans profile="tiles3">
		<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.tiles3.TilesViewResolver">
			<property name="order" value="0"/>
		</bean>
	
		<!-- Configures Tiles 3-->
		<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
			<property name="definitions">
				<list>
					<value>/WEB-INF/view/jsp/03-tiles/tiles.xml</value>
					<value>/WEB-INF/view/jsp/admin/tiles.xml</value>
				</list>
			</property>
		</bean>
	</beans>
	
	<beans profile="tiles2">
		<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.tiles2.TilesViewResolver">
			<property name="order" value="0"/>
		</bean>
	
		<!-- Configures Tiles 2 -->
		<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
			<property name="definitions">
				<list>
					<value>/WEB-INF/view/jsp/03-tiles/tiles.xml</value>
					<value>/WEB-INF/view/jsp/admin/tiles.xml</value>
				</list>
			</property>
		</bean>
	</beans>

</beans>

/WEB-INF/view/jsp/03-tiles/tiles.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC 
	"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" 
	"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">	

<tiles-definitions>

	<definition name="03-tiles/*" template="/WEB-INF/view/jsp/03-tiles/layout.jsp">
		<put-attribute name="main" value="/WEB-INF/view/jsp/03-tiles/{1}.jsp" />
	</definition>
	
</tiles-definitions>

/WEB-INF/view/jsp/03-tiles/layout.jsp

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>

<html>
<head>
	<meta charset="utf-8"/>
	<spring:url value="/common/style" var="styleUrl" />
	<link href="${styleUrl}/app.css" rel="stylesheet"/>
	<title><c:out value="${title}"/></title>
</head>

<body>
	<div class="container" style="padding-top: 50px;">
		<jsp:include page="/WEB-INF/view/jsp/menu.jsp"/>	
		<tiles:insertAttribute name="main" />
		<jsp:include page="/WEB-INF/view/jsp/footer.jsp"/>	
	</div>
</body>
</html>
728x90
728x90

출처 : Mobile Tutorial: Using InterBase ToGo (iOS and Android)
http://www.pclviewer.com/android/
Linux Certif - dlopen
Getting the Battery Level on Android With Delphi
XE4 Mobile Tip #2 ? Loading local HTML content
Android/SQLite 공유 라이브러리를 이용하는 C로 프로그램 작성
Delphi XE4 with iOS / #08. Hello World without Firemonkey
Thread: What is the right procedure to add the additional framework on iOS ?
Unable to dlopen(libsomething.so) Cannot load library: link_image[1995]: failed to link libsomething.so

정적 라이브러리 참조

Androidapi.Log.pas (델파이 일부 소스 발취)

unit Androidapi.Log;

interface

{$I Androidapi.inc}

type
  android_LogPriority = (
    ANDROID_LOG_UNKNOWN,
    ANDROID_LOG_DEFAULT,
    ANDROID_LOG_VERBOSE,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_INFO,
    ANDROID_LOG_WARN,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_FATAL,
    ANDROID_LOG_SILENT
 );
 {$EXTERNALSYM android_LogPriority}


function __android_log_write(Priority: android_LogPriority; const Tag, Text: MarshaledAString): Integer; cdecl;
  external AndroidLogLib name '__android_log_write';
 {$EXTERNALSYM android_LogPriority}

{ Helper functions }
function LOGI(Text: MarshaledAString): Integer;
...

implementation

function LOGI(Text: MarshaledAString): Integer;
begin
  Result := __android_log_write(android_LogPriority.ANDROID_LOG_INFO, 'info', Text);
end;

...

end.

정적라이브러리 소스

testlib.h

/*
 * testlib.h
 *
 *  Created on: 2012. 9. 6.
 *      Author: bluexmas
 */
 
#ifndef LIBTEST_H_
#define LIBTEST_H_
 
extern const char* get_version();
 
#endif /* LIBTEST_H_ */

testlib.c

/*
 * testlib.cpp
 *
 *  Created on: 2012. 9. 6.
 *      Author: bluexmas
 */
 
#include "testlib.h"
 
const char* get_version() {
  return "testlib ver 0.1";
}

Makefile

ANDROID_NDK_ROOT = /opt/android-ndk-r9
NDK_TOOLCHAIN_VERSION = 4.6
TOOLCHAIN = /opt/android-9-toolchain

CROSS  = $(TOOLCHAIN)/bin/arm-linux-androideabi-
INCDIR = $(TOOLCHAIN)/sysroot/usr/include
LIBDIR = $(TOOLCHAIN)/sysroot/usr/lib

CC     = $(CROSS)gcc
AR     = $(CROSS)ar $(ARFLAGS) r
RANLIB = $(CROSS)ranlib
NM     = $(CROSS)nm

CFLAGS = -g $(INC) -fPIC 

TARGET = libtest.so

OBJS = testlib.o
#SRCS = testlib.c

.SUFFIXES : .c .o 

all : $(TARGET)

$(TARGET) : $(OBJS)
	$(CC) -shared -Wl,-soname,$@ -o $@ $(OBJS)

dep :
	gccmakedep $(INCDIR) $(SRCS)

clean :
	rm -rf $(OBJS) $(TARGET) core

 컴파일

파일

testlib.h /testlib.c /Makefile

위에서 만들어진 정적 라이브러리 파일을 /sdcard 폴더에 복사한 뒤(직접복사), 동적으로 로딩하여 get_version 함수룰 호출하는 예제입니다. library\lib\armeabi\ 경로에서 상대경로로 읽으려고 했지만, 절대경로만 인식하는 것 같습니다. 참고 자료가 별로 없어 확인 할 수 없었습니다.

Unit2.pas

unit Unit2;

interface

uses
  Classes, SysUtils, SyncObjs,
  System.IOUtils, Posix.Dlfcn;

//function __get_version(): MarshaledAString; cdecl; external '/sdcard/libtest.so' name 'get_version';

type
  _get_version = function(): MarshaledAString; {$IFNDEF CLR}cdecl;{$ENDIF}

function LoadLib() : IntPtr;

var
  get_version : _get_version;

implementation

function LoadLib() : IntPtr;
begin
  //
  //hLiteLib2 := dlopen(MarshaledAString(GetHomePath() + PathDelim + 'libtest.so'), RTLD_LAZY);
  //hLiteLib2 := dlopen(MarshaledAString(TPath.Combine(TPath.GetDocumentsPath, 'libtest.so')), RTLD_LAZY);
  Result := dlopen(MarshaledAString('/sdcard/libtest.so'), RTLD_LAZY);

  if NativeUInt(Result) > 0 then begin
    get_version := dlsym(Result, MarshaledAString('get_version'));
  end;
end;

Initialization
  get_version := nil;

end.

Unit1.pas

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types,
  FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.WebBrowser, FMX.StdCtrls, FMX.Layouts,
  FMX.Edit, FMX.Memo;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    hLiteLib: IntPtr;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  System.IOUtils, Unit2;

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  //ShowMessage(TPath.Combine(TPath.GetDocumentsPath, 'libtest.so'));

  hLiteLib := LoadLib();
  if NativeUInt(hLiteLib) = 0 then begin
    ShowMessage('Cannot load client library: ' + 'libtest.so');
  end;

  if Assigned(get_version) then begin
    Edit1.Text := get_version(); // IntToStr( hLiteLib );
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Memo1.Lines.LoadFromFile(TPath.Combine(TPath.GetDocumentsPath, 'memo.txt'));
end;

end.

Deployment 화면

실행결과

실행결과 Button1 선택

실행결과 Button2 선택

728x90
728x90

출처 : Installing the Android Development Tools
Android Mobile Application Development
DELPHI XE4에서 FireMonkey Mobile용 컴포넌트 추가하기.

1. ShowModal 사용하기 그리고 문제점
ShowModal Dialogs in FireMonkey Mobile Apps

XE5에서 안드로이드의 경우 기존과 동일한 ShowModal를 지원하지 않는 것 같습니다.
안드로이드의 경우 모든 화면 제어가 쓰레드로 동작하기 때문에 기존의 ShowModal를 지원 못하는게 아닌가 싶습니다.

기존 코드

function GetConnectionInfo(AOwner: TComponent): TDBConnection;
var
  FConnect: TFConnect;
begin
  Result := nil;
  FConnect := TFConnect.Create(AOwner);
  try
    if FConnect.ShowModal = mrOk then
    begin
      Result := FConnect.ResultDBConnection;
    end;

  finally
    FConnect.Free;
  end;
end;

수정된 코드

var
  FConnect: TFConnect;           // 전역변수

function GetConnectionInfo(AOwner: TComponent; OnDBConnected : TNotifyEvent): TDBConnection;
var
  ConnectFormBase: TConnectFormBase;
begin
  Result := nil;
  try
    if Assigned(FConnect) then begin
      FConnect.Show;
    end else begin
      FConnect := TFConnect.Create(AOwner);
      FConnect.OnDBConnected := OnDBConnected;
      FConnect.ShowModal(procedure(ModalResult : TModalResult)
      begin
        if ModalResult = mrOk then begin
          FConnect.DoConnect();
          if Assigned(Self.OnDBConnected) then begin
            FConnect.OnDBConnected(FConnect.ResultDBConnection);
          end;
        end;
        if Assigned(FConnect) then
          FConnect.DisposeOf;
        FConnect := nil;

        frmMDIMain.Invalidate;
      end);
    end;
  except
    on e : Exception do
      ShowMessage(e.Message);
  end;
end;

지금 까지 찾아낸 문제점

1. ShowModal의 결과 값을 이벤트 형태로 받아 합니다.

FConnect.ShowModal(procedure(ModalResult : TModalResult)
begin
  f ModalResult = mrOk then begin
    // mrOk인 경우 처리
  end;

  // 화면 닫기
  frmMDIMain.DisposeOf;
end);

문제점1 : 변수 사용의 불편함 / In-Line으로 procedure를 구현하므로 전역으로 정의된 변수를 제외하고는 접근이 되지 않음

문제점2 : FormClose 호출 시점 

기존에는 if FConnect.ShowModal = mrOk then 이후 문장이 실행 되기 전에 FormClose가 호출 되었지만,
XE5 안드로이드의 경우 DisposeOf가 호출 시점에 FormClose가 호출 됩니다.

CallBack 이벤트 함수(OnDBConnected 함수)를 만들어서 처리했습니다.

2. 기존에 ShowModal 처럼 정지(?) 되지 않습니다.

문제점1ShowModal 이후 문장이 그대로 실행 됩니다.

ShowModal 이후 문장인 finally 가 바로 실행(FConnect.Free; 실행) 되어 화면이 나타났다가 빠르게 사라집니다.

문제점2 : 정지 되지 않기 때문에 ShowModal 호출하는 이벤트를 다시 호출하면 두개의 화면이 생성됩니다.

Form 변수인 FConnect 를 전역 변수로 선언하고, Assigned 유효 한지 체크하고, 종료시 FConnect := nil; 로 초기화 했습니다.

문제점3 : FireMonkey가 느려서 닫기 버튼을 두번 누르면, DisposeOf 가 두번 호출 되면서 FConnect가 닫혀지고, Main 화면까지도 닫아 지는 것 같은 문제가 있습니다. (버그로 의심됨)

문제점4 DisposeOf 가 호출되고 Main 화면이 나타나야 할 텐데, 화면이 그대로 남아 있어, Main 폼의 frmMDIMain.Invalidate; 를 호출해야 보여집니다. (버그로 의심됨)

- end -

728x90
728x90

다운로드

http://old-releases.ubuntu.com/releases/oneiric/

NDK 다운로드

http://developer.android.com/tools/sdk/ndk/index.html

SSH 서버 설치
http://pirtaja.tistory.com/9

$ sudo apt-get install openssh-server
$ sudo /etc/init.d/ssh restart

jdk 1.6 설치 (Gingerbread and newer)
Installing Java6 JDK on Ubuntu 11.10

$ sudo add-apt-repository ppa:ferramroberto/java
$ sudo apt-get update
$ sudo apt-get install sun-java6-jdk sun-java6-plugin

.bashrc 내용 추가

# Java Setting
export JAVA_HOME=/usr/lib/jvm/java-6-sun
export ANDROID_JAVA_HOME=$JAVA_HOME

Android PDK 빌드 환경 구축 (64Bit OS)
http://source.android.com/source/initializing.html
[Android/안드로이드] Ubuntu에서 E: Package 'lib32readline5-dev' has no installation candidate. 발생시 대처 방법.

$ sudo apt-get install git-core gnupg flex bison gperf build-essential \
  zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs \
  x11proto-core-dev libx11-dev lib32readline-gplv2-dev lib32z-dev \
  libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown \
  libxml2-utils xsltproc

Libx11-dev:i386 설치

$ sudo apt-get install libx11-dev:i386

repo 스크립트 다운로드
[Android/안드로이드] 64bit Ubuntu Android ICS Source 다운받기

$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
$ chmod a+x ~/bin/repo

저장소 초기화

$ sudo mkdir /opt/android-source
$ cd /opt/android-source
$ sudo chown test:test .            <-- 옵션
$ repo init -u https://android.googlesource.com/platform/manifest
$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.3_r1

소스 내려 받기

$ repo sync

안드로이드 소스 전체빌드
[안드로이드] 안드로이드 소스 전체빌드 해보기
안드로이드 빌드하기

안드로이드 소스 빌드

$ cd /opt/android-source
$ make

빌드 오류 해결법

android build error 해결법
ICS Source download
slang_rs_export_foreach.cpp , error : variable ‘ParamName’ set but not used
Ubuntu 11.10 ics build error

make: *** [out/host/linux-x86/obj/EXECUTABLES/obbtool_intermediates/Main.o] Error 1

$ vi build/core/combo/HOST_linux-x86.mk
#HOST_GLOBAL_CFLAGS += -D_FORTIFY_SOURCE=0
HOST_GLOBAL_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libGLcommon_intermediates/GLDispatch.o] Error 1

$ sudo apt-get install mesa-common-dev

make: *** [out/host/linux-x86/obj/EXECUTABLES/llvm-rs-cc_intermediates/slang_rs_export_foreach.o] Error 1

$ vi frameworks/compile/slang/Android.mk
#local_cflags_for_slang := -Wno-sign-promo -Wall -Wno-unused-parameter -Werror
local_cflags_for_slang := -Wno-sign-promo -Wall -Wno-unused-parameter

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/liboprofile_pp_intermediates/arrange_profiles.o] Error 1

external/oprofile/libpp/format_output.h 파일의 94번행

-   mutable counts_t & counts;
+   counts_t & counts;

make: *** [out/host/linux-x86/obj/EXECUTABLES/test-librsloader_intermediates/test-librsloader] Error 1

external/llvm/llvm-host-build.mk 내용 추가

+   LOCAL_LDLIBS := -lpthread -ldl

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libgtest_host_intermediates/gtest-all.o] Error 1

vi external/gtest/include/gtest/internal/gtest-param-util.h 내용추가

#include <cstddef>

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libMesa_intermediates/src/glsl/linker.o] Error 1

vi external/mesa3d/src/glsl/linker.cpp 내용추가

#include <stddef.h>

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libmtp_intermediates/MtpDevice.o] Error 1

vi frameworks/base/media/mtp/MtpDevice.cpp 수정

-   int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
+   int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, 0777);

Android NDK(C/C++) 설치

http://developer.android.com/tools/sdk/ndk/index.html

$ sudo mv android-ndk-r9-linux-x86_64.tar.bz2 /opt
$ sudo tar xvf android-ndk-r9-linux-x86_64.tar.bz2

.profile-ndk 파일 작성

export ANDROID_NDK_ROOT=/opt/android-ndk-r9
export NDK_TOOLCHAIN_VERSION=4.6
export TOOLCHAIN=/opt/android-9-toolchain

export PATH=$TOOLCHAIN/bin:$PATH

.profile-ndk 실행 (NDK 빌드시 사용)

$ chmod a+x .profile-ndk 
$ source .profile-ndk

ToolChain 만들기

$ $ANDROID_NDK_ROOT/build/tools/make-standalone-toolchain.sh \
--toolchain=arm-linux-androideabi-4.6 \
--ndk-dir=$ANDROID_NDK_ROOT \
--install-dir=$TOOLCHAIN \
--platform=android-9
$ sudo chown test:test -hR /opt/android-9-toolchain

728x90
728x90

출처 : 안드로이드(Android) 유니티(Unity3D) 연동 ,값전달, Toast, Dialog 등...
[android] 메시지 핸들러(Handler) 사용하기
[안드로이드] 유니티 C# 클래스와 자바 클래스간의 연동
Trying to create a simple AlertDialog plugin, crash occurs
Platform Dependent Compilation
20. 카드 짝찾기 게임(7) - 안드로이드용으로 변환 (Keystore 사용 빌드)

Unity에서 Android Activity와 연동하기 위해 Unity C# 소스 작성

Unity의 AndroidJavaObject 객체를 이용해서 Android에 호출하고 호출한 결과값은 바로 받을 수 없어 로직이 끝나고 다시 Android Activity에서 Unity C# 함수를 호출해서 결과 값을 받을 수 있습니다.

아래 예제는 Cs_CubeManager을 싱글톤 객체로 만들어서 AndroidJavaObject 객체를 Unity 전체에서 사용하도록 했으며, Cs_AndroidManager에서 AndroidJavaObject 객체를 할당 받도록 했습니다.

Android호출시 다른 Activity를 생성하거나 Toast 메시지 출력시 아래와 같이 오류가 발생하므로 Handle 사용해야 합니다.

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

개발시나 iOS에서는 동작하지 않도록 preprocessor로 UNITY_ANDROID를 사용하여, Android에서만 동작할 수 있도록 소스작성 합니다.

#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    public AndroidJavaObject activity = null;
#endif	

Android Activity와 연동하기 위해서 C# AndroidJavaObject 객체를 아래와 같이 할당 받아야 합니다.

AndroidJavaObject activity = null;

AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
cubeMng.activity = jc.GetStatic<AndroidJavaObject>("currentActivity");

AndroidJavaObject 객체의 Call 메소드를 호출 하여 Android Activity의 메소드를 호출합니다.

	public void NativeAlert(string message) {
#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    	activity.Call("AlertMessage", message);
#endif			
	}

Cs_AndroidManager.cs

using UnityEngine;

public class Cs_AndroidManager : MonoBehaviour {
	
    //private static Cs_AndroidManager _instance = null;
	
	private Cs_CubeManager cubeMng;

    public string androidLog = "No Log";
	
    void Start() {				
		cubeMng = Cs_CubeManager.getInstance();
		cubeMng.device_model = "test";		
#if UNITY_ANDROID
		AndroidCall();
#endif		
	}
	
#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    //public AndroidJavaObject activity = null;

    void AndroidCall()
    {
        // 현재 실행 중인 유니티 액티비티를 가져와서 변수에 저장.
        //AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
		AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        cubeMng.activity = jc.GetStatic<AndroidJavaObject>("currentActivity");
		cubeMng.activity.Call("initActivity", "Cs_AndroidManager");
    }
#endif	

    // 자바 클래스로부터 전달받은 로그를 보여줍니다.
    public void AndroidLog(string newAndroidLog) {
        androidLog = newAndroidLog;
    }
	
	public void SetCountryCode(string code) {
		cubeMng.country_code = code;
	}
	
	public void SetDeviceID(string did) {
		cubeMng.device_id = did;
	}
	
	public void SetDeviceModel(string dModel) {
		cubeMng.device_model = dModel;
	}	
	
	/*
    public static Cs_AndroidManager Instance
    {
        get
        {
            if (_instance == null)
            {
				
				Debug.Log("------------- _instance.0 = " + _instance);
				
                _instance = FindObjectOfType(typeof(Cs_AndroidManager)) as Cs_AndroidManager;
				
				Debug.Log("------------- _instance.1 = " + _instance);
				
                if (_instance == null)
                {
                    _instance = new GameObject("Cs_AndroidManager").AddComponent<Cs_AndroidManager>();
                }
				
				Debug.Log("------------- _instance.2 = " + _instance);
            }

            return _instance;
        }
    }
    */
}

Cs_CubeManager.cs

using UnityEngine;
using System;

public class Cs_CubeManager {
	
	// 싱글톤 인스턴스 
	private static Cs_CubeManager instance = null;
	
	public string country_code = "KOR";
	
	public string device_id = "";
	
	public string device_model = "";	
	
#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    public AndroidJavaObject activity = null;
#endif	

	private Cs_CubeManager() {
/*
		if (Camera.mainCamera != null && Camera.mainCamera.GetComponent("WWWWiki") != null)
			wWWWiki = Camera.mainCamera.GetComponent("WWWWiki") as WWWWiki;
*/
	}
	
	public static Cs_CubeManager getInstance() {
		if (instance == null) {
			instance = new Cs_CubeManager();
		}
		return instance;
	}
		
	public void NativeAlert(string message) {
#if UNITY_ANDROID 
    // 유니티가 동작하는 액티비티를 저장하는 변수.
    	activity.Call("AlertMessage", message);
#endif			
	}	
}

Unity3D 에서 Android 소스로 Export 하기

1. 메뉴 [Build Settings...] 선택합니다.

2. [Build Settings] 화면에서 Platform 목록에서 Android 항목을 선택합니다.

3. Bundle Identifier에 Android에서 사용할 Package 명을 입력합니다.

4. 다시 [Build Settings] 화면에서 Create Eclipse project 체크 박스를 선택하고, 버튼 [Export]을 선택합니다.

5. Export 받을 경로를 선택하고, 버튼 [폴더 선택]을 선택합니다.

6. 탐색기로 아래와 같이 Export 받은 파일 목록을 확인 합니다.

파일 목록에서 classes.jar 파일을 확인 할 수 있는데,
C:\Program Files (x86)\Unity\Editor\Data\PlaybackEngines\androidplayer\bin 폴더의 classes.jar 파일과 동일한 파일로
Unity에서 Export 받으면 자동으로 classes.jar 파일을 복사해서 빌드 라이브러리에 자동으로 추가 됩니다.

7. [Package Explorer] 에서 오른쪽 버튼을 선택해서, 팝업 메뉴에서 메뉴 [Import...]를 선택합니다.

8. 메뉴 [Existing Projects into Workspace]를 선택합니다.

9. 버튼 [Browse...]을 선택합니다.

10. Unity에서 Export 받은 폴더를 선택합니다.

11. 버튼 [Finish]을 선택합니다.

12. Import 된 파일 목록을 확인합니다.

Android 소스 작성

Unity에서 Export 받은 소스에는 UnityPlayerActivity 를 상속 받지 않아서,
UnityPlayerActivity 겍체를 상속 받아 CubeMainActivity 소스를 작성하고, AndroidManifest.xml에서 Main Activity를 CubeMainActivity 수정했습니다.

Unity에서 호출 받은 로직을 처리하기 위해서 Handler 상속 받아서 Unity3DHandler.java 소스를 작성합니다.

CubeMainActivity.java

package com.azanghs.cube;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.example.android.trivialdrivesample.util.IabHelper;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

public class CubeMainActivity extends UnityPlayerActivity {
	
	private static String TAG = CubeMainActivity.class.getSimpleName();
	
	private TelephonyManager m_telephonyManager;
	
	String androidId = "KOR";	
	
    // The helper object
    IabHelper mHelper;
    
    private Unity3DHandler handler = null;
    
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       handler = new Unity3DHandler(this);

       m_telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
     
       Log.i(TAG, "Build.MODEL = " + Build.MODEL);
       Log.i(TAG, "Build.DEVICE = " + Build.DEVICE);
       Log.i(TAG, "Build.PRODUCT = " + Build.PRODUCT);
   }
   
	@Override
	public void onBackPressed() {
		this.finishMessage();
	}
	
	public void QuitApplication() {
		handler.sendEmptyMessage(0);
	}
	
	public void AlertMessage(final String message) {
		Message msg = handler.obtainMessage(1);
		msg.obj = message;
		handler.sendMessage(msg);
	}
	
	public void finishMessage() {
		new AlertDialog.Builder(this).setMessage("프로그램을 종료하시겠습니까?")
		.setPositiveButton("확인", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				//System.exit(0);
				UnityPlayer.UnitySendMessage("GameObject", "FinishApp", "");
			}
		}).setNegativeButton("취소", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
			}
		}).show();	
	}

   //요 부분입니다. 이걸... Thread가 불필요하다면 
   public void initActivity(final String messageFromUnity)
   {
	   
	   Log.i(TAG, "여기 호출 Build.MODEL = " + Build.MODEL);
	   
       UnityPlayer.UnitySendMessage("GameObject", "SetCountryCode", getResources().getConfiguration().locale.getISO3Country());
       UnityPlayer.UnitySendMessage("GameObject", "SetDeviceModel", Build.MODEL);       

       // 디바이스 ID
       String androidId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);       
       UnityPlayer.UnitySendMessage("GameObject", "SetDeviceID", androidId);
	   
       //
       //UnityPlayer.UnitySendMessage("Cs_AndroidManager", "AndroidLog", "4/[" + tagFromUnity + "]" + messageFromUnity);
   }

   public void alert(String message) {
       AlertDialog.Builder bld = new AlertDialog.Builder(this);
       bld.setMessage(message);
       bld.setNeutralButton("OK", null);
       Log.d(TAG, "Showing alert dialog: " + message);
       bld.create().show();
   }  
}

Unity3DHandler.java

package com.azanghs.cube;

import android.os.Handler;
import android.os.Message;

public class Unity3DHandler extends Handler {
	
	private CubeMainActivity mainActivity = null;
	
	public Unity3DHandler(CubeMainActivity mainActivity) {
		this.mainActivity = mainActivity;
	}
	
	public void handleMessage(Message msg) {
		switch (msg.what) {
		case 0:
			mainActivity.finishMessage();
			break;
		case 1:
			mainActivity.alert((String)msg.obj);
			break;			
		default:
			break;
		}		
	}
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="preferExternal" android:theme="@android:style/Theme.NoTitleBar" package="com.azanghs.cube" android:versionName="1.0" android:versionCode="1">
  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false">
    <activity android:name=".CubeMainActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|uiMode|touchscreen" android:screenOrientation="portrait">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>       
    <!--       
    <activity android:name="com.azanghs.cube.CubeProxyActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="portrait">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name="com.azanghs.cube.CubeActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="portrait">
    </activity>
    <activity android:name="com.azanghs.cube.CubeNativeActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="portrait">
      <meta-data android:name="android.app.lib_name" android:value="unity" />
      <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
    </activity>
    -->
  </application>
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-feature android:name="android.hardware.touchscreen" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
  <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17" />
</manifest>

Android 프로젝트를 Unity Plugin Jar로 Export 하기

1. 해당 프로젝트를 선택하고 메뉴 [Export...] 선택합니다.

2. 메뉴 [JAR file] 선택합니다.

3. 아래와 같이 선택합니다.
Jar 파일이 생성되는 파일 경로 Unity 소스 폴더의 %소스경로%\Assets\Plugins\Android 로 합니다. (변경불가)

4. 버튼 [Next >] 버튼 선택합니다.

5. 버튼 [Finish] 버튼 선택합니다.

6. Unity에서 Build 하면 Android 폰에 실행된 결과를 확인 할 수 있습니다.

- 설명 작성하려니 귀찬니즘이 발생해서 나중에 시간이 나면 다시 작성하도록 하겠음

728x90
728x90

Android Back 버튼 이벤트 ( 출처 : 원숭이가 만드는 게임 )

if ( Input.GetKeyDown(KeyCode.Escape) )  {
    // 안드로이드 Back버튼 눌렀을때 처리
}

Unity3D에서의 Singleton 사용
( 출처 : Unity3D에서의 singleton 패턴, Unify Community - Singleton,  Global Managers With Generic Singletons )

Unity3D - Android 연동
(출처 : 유니티4! 짜증나는 이클립스 연동 한방에 끝내보자[안드로이드] 유니티 C# 클래스와 자바 클래스간의 연동 )

Android - android id 구하기
( 출처 : Samsung developers - Android - Technical Docs )

Android - 국가코드 가져오기
( 출처 : 단말 정보들 가져오기 )

동적으로 ButtonMessage에 target설정 / onClick 클릭 객체 가지고 오기
( 출처 : Topic: How to detect if mouse is clicking on NGUI area? )
void createItem() {
  obj = Instantiate(
    opengame,
    new Vector3(
      opengame.transform.position.x+(0.5f*(i-1)+k*1.5f),
      opengame.transform.position.y-j,
      opengame.transform.position.z
    ), 
    Quaternion.identity
  ) as GameObject;
  UIButtonMessage btnMessage = obj.GetComponent("UIButtonMessage") as UIButtonMessage; 
  btnMessage.target = btnMessageTarget;
}

void OnOpenStageClick() {
  Debug.Log("Clicked " + UICamera.hoveredObject);
  Cs_loadgameclick script_load = UICamera.hoveredObject.GetComponent("Cs_loadgameclick") as Cs_loadgameclick; 
  Debug.Log("targetstage = " + script_load.targetstage);
}

asfd

- end -


728x90
728x90

출처 : 유니티에서 데이터 저장하기 #1

DataUser.cs

using UnityEngine;
using System.Collections;

public class DataUser {

	private string m_user_name;
	public string UserName {
		get {
			return m_user_name;
		}
		set {
			m_user_name = value;
		}
	}
	
	private string m_nick_name;
	public string NickName {
		get {
			return m_nick_name;
		}
		set {
			m_nick_name = value;
		}
	}
	
}

Main.cs

using UnityEngine;
using System.Collections;

public class Main : MonoBehaviour {
	
	// Use this for initialization
	void Start () {
		/*
		DataUser user = GetUserData();
		user.UserName = "test";
		user.NickName = "blue";
		
		SaveUserData(user);
		*/
		
		DataUser user = GetUserData();
		Debug.Log( user.UserName );
		
	}
	
	void SaveUserData(DataUser user) {
		PlayerPrefs.SetString("UserName", user.UserName);
		PlayerPrefs.SetString("NickName", user.NickName);		
	}
	
	DataUser GetUserData() {
		DataUser user = new DataUser();
		user.UserName = PlayerPrefs.GetString("UserName");
		user.NickName = PlayerPrefs.GetString("NickName");
		return user;
	}
}

 

728x90
728x90

출처 : android.os.NetworkOnMainThreadException 예외가 발생했을 경우
android.os.NetworkOnMainThreadException
http://aroundck.tistory.com/1240

사용예

        if(android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }
        
        String test;
		try {
			test = HttpCallUtils.call("aaa", "bbb");
			System.out.println("test = " + test);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

HttpCallUtils

package com.test;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;

public class HttpCallUtils {

	private static String url = "https://test.com/login_check.php";
	private static String key_user = "mb_id";
	private static String key_password = "mb_password";	
	
	/*
	public static void main(String[] args) throws Exception {
		String test = HttpCallUtils.call("aaa", "bbb");
		System.out.println("test = " + test);
	}
	*/
	
	public static String call(String parma1, String param2) throws Exception {
		
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(url);

		HttpParams params = client.getParams();
		params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,HttpVersion.HTTP_1_1);
		params.setParameter(CoreConnectionPNames.SO_TIMEOUT, new Integer(15000));
		params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, new Integer(15000));

		ArrayList<BasicNameValuePair> nameValuePairs = new ArrayList<BasicNameValuePair>();
		nameValuePairs.add(new BasicNameValuePair(key_user, parma1));
		nameValuePairs.add(new BasicNameValuePair(key_password, param2));
		UrlEncodedFormEntity entityRequest = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
		post.setEntity(entityRequest);
		
		//
		HttpResponse response = client.execute(post);
		
		StringBuffer sb = new StringBuffer();

		// Examine the response status
		System.out.println(response.getStatusLine());

		// Get hold of the response entity
		HttpEntity entity = response.getEntity();

		// If the response does not enclose an entity, there is no need
		// to worry about connection release
		if (entity != null) {
			InputStream instream = entity.getContent();
			try {
				BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
				// do something useful with the response
				String line;
				while ((line = reader.readLine()) != null)
					sb.append(line+"\n");
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				instream.close();
			}
		}	
		return sb.toString();
	}	
}

 

728x90

+ Recent posts