이클립스에서 안드로이드 스투디오로 이동하기

2015년 3월 현재 안드로이드 개발자에게는 선택할 수 있는 IDE가 아래와 같이 3종류이다.

  • ADT(Android Developer Tools, 이클립스 기반)
  • 인텔리제이 커뮤니티 에디션(Intelli J 무료 버전)
  • Android Studio(Intelli J 기반의 무료 IDE)

하지만, 구글 공식 IDE는 Android Studio이다. 아직, ADT를 다운로드 받을 수 있지만 이전 글처럼 지원이 종료되었고, Android Studio가 Develop > Tools의 첫 페이지에 있는 것과 달리 ADT페이지는 이미 저 안쪽에 숨겨져 있고 Android Studio 프로젝트로 전환하는 방법이 먼저 보이며, 다운로드 받는 링크를 찾기는 이미 힘들다.

이 소식을 알자마자, 열혈개발자인 나는 구글의 제안에 따라 Android Studio를 사용하기로 결심해버렸다. 내 주변 개발자들은 아직도 ADT를 쓰고 있지만, 나만 바꾸면 되지 않겠나?

이클립스, 인텔리제이 그리고 안드로이드스투디오

아마도 내 마음과 달리 잘 안될 수 있다. 위 세가지 IDE가 지원하는 안드로이드 프로젝트 타입이 다르기 때문이다. 각각 어떤 안드로이드 프로젝트 타입을 지원할까. 안드로이드 스투디오 이동을 염두하여 중요한 프로젝트만 열거해보자.

  • 이클립스
    • 이클립스 프로젝트
  • 인텔리제이
    • 인텔리제이 프로젝트
    • (Gradle로 빌드되는) 인텔리제이 프로젝트
  • 안드로이드 스투디오
    • 인텔리제이 프로젝트
    • Gradle 기반 안드로이드 프로젝트(위의 Gradle을 빌드스크립트로만 쓰는 경우와는 다름)

위 내용만 보면, 이클립스 프로젝트를 안드로이드 스투디오에서 잘 import 해서 쓰면 되겠지 싶다. 하지만 안드로이드 스투디오에서 지원하는 프로젝트 종류에는 크게 두가지 문제가 있다.

  • 안드로이드 스투디오에서는 새 인텔리제이 안드로이드 프로젝트를 만들 수 없고, 열 수만 있다.
  • 안드로이드 스투디오에서 이클립스나 인텔리제이 기반 안드로이드 프로젝트를 Gradle 기반의 안드로이드 프로젝트로 import할 때 폴더구조가 완전히 바뀐다.

위와 같은 제약으로 인해, 팀 내 혼자서 안드로이드 스투디오로 이동하면 다른 IDE(특히 이클립스)를 사용하는 개발자와 같은 VCS를 쓸 수가 없다.

그럼 어떻게 IDE를 변경해야 하나?

먼저 개인 개발자라면, 그냥 바꾸면 된다. 폴더 구조가 바뀌는 것은 번거롭지만 한번만 하면 되니 어쨌든 상관 없다.

같은 프로젝트를 여러사람과 개발하고 있다면 좀 머리아프다.  아래와 같이 정리할 수 있다.

  • 이쯤되니 머리가 아프다. 그냥 ADT 쓴다. (좋은 생각이다.)
  • 인텔리제이에서는 이클립스의 폴더구조를 바꾸지 않고도, 안드로이드 프로젝트를 만들 수 있다. 게다가, 안드로이드 스투디오의 좋은 기능들을 대부분 지원하고 있다. 그러므로, 안드로이드 스투디오 대신에 인텔리제이 커뮤니티 에디션(무료)를 사용하고, 프로젝트 파일(.iml)파일은 로컬에만 두고 쓴다.
  • ‘가려면 안드로이드 스투디오로 가야지 무슨 인텔리제이냐’라고 생각한다면, 인텔리제이와 안드로이드 스투디오를 모두 사용하는 방법을 생각할 수 있다. 이클립스 프로젝트를 인텔리제이에서 import한 후에(즉, 인텔리제이 프로젝트로 변환), 이를 안드로이드 스투디오에서 열면 된다. 안드로이드 스투디오에서는 새 인텔리제이 프로젝트를 만들 수 없을 뿐 열 수 있기 때문이다. 물론, 모듈(이클립스의 프로젝트와 같은 개념의 단어)을 추가할 때마다 인텔리제이를 열어야겠지만,  역시 나만 조심해서 쓰면 된다.
  • 마지막 방법은 어쩌면 쉬울 수 있다. 일단, 모두 퇴근할 때까지 기다린 후에 이클립스 프로젝트를 안드로이드 스투디오를 통해 Gradle 기반 프로젝트로 변환(폴더구조를 바꾸어 사본 프로젝트를 만들어준다.)한 후에 이를 VCS에 올리고 집에 간다. (조금 더 배려하고 싶다면, 다른 개발자들의 컴퓨터에 안드로이드 스투디오를 설치해줄 수 있다.)

마지막 방법은 물론 농담이다. 위 방법들을 보면 알겠지만, 팀내에서 혼자서만 안드로이드 스투디오로 IDE를 바꾸기는 어렵다. 물론 .gradle 파일을 고쳐 볼 수도 있겠지만, 안드로이드 스투디오에서 제안하는 구조와 방법들로는 어렵다. 너무 무리한 변경이 아니었나도 싶지만, 일단 옮기고 나면 분명 장점이 있다. 그러니, 안드로이드 스투디오로 옮길 때에는 팀 내 의견을 조율하여 함께 진행하는 것이 정답이다. 

그 밖에 사소하지만 큰 문제들

인텔리제이는 많은 플러그인을 제공한다. 단, 프로페셔널 버전(유료)에 한해서다. 인텔리제이 커뮤니티 에디션(무료)이나 안드로이드 스투디오의 경우, 자신이 사용하는 형상관리 시스템(VCS)과 연동이 되는지 꼭 확인해야한다. 현재 안드로이드 스투디오에서 연동이 가능한 대표적인 형상관리 시스템은 다음과 같다.

  • Git
  • Subversion(SVN)
  • CVS
  • Mercurial

지원되지 않은 대표적인 형상관리 시스템은 아래와 같다.

  • Perforce
  • Clear Case

참고로, Perforce 같은 경우는 무료 플러그인이 한참 개인 개발자에 의해 만들어지고 있으나 만족스럽지 않다.

맥에서 인텔리제이를 위한 JDK 설정

오라클 사에서는 맥을 위한 JDK도 지원한다. JDK8까지 지원하고 다운받아서 설치만 하면 기본 JDK 정보도 바꿔준다. 설정이 잘 되었는지 확인하고 싶다면 터미널에서 java나 javac의 버전을 확인해보거나, 오라클에서 제공하는 테스트 페이지에서 시험해보면 된다.

그런데, 인텔리제이는 최신버전(현재 14)설치해도 아래와 같은 메시지를 보이면서 Apple 사의 JDK 6(현재 최신)를 설치하라고 한다.

Screen Shot 2014-11-09 at 23.53.02

JDK 설정을 찾지못해서 보여주는 일종의 버그라고 생각했는데 아니었다. 인텔리제이 사의 서포트 페이지를 보면 그 이유가 열거되어 있다. 간단히 요약하면, 오라클 사의 맥용 JDK가 맥에서 동작할 때 버그가 있어서 여전히 애플 사의 JDK 6를 사용한다는 것이다.

그러니, 인텔리제이를 구동하기 위해서라면 윈도우 셋팅하듯 최신 버전 JDK 설치하지 말고, 애플의 JDK 6를 사용하자.

참고로, 위의 설정은 인텔리제이를 위한 JDK 설정으로 인텔리제이를 실행한 후에는 JDK를 추가할 수 있다. 이 때, 오라클 사의 JDK를 추가해서 프로젝트에 사용할 수 있다.

Screen Shot 2014-11-10 at 01.01.46

그 밖에

스택오버플로우에 보면 인텔리제이를 JDK 7에서 동작시키는 방법들이 나와있지만, 보통은 애플의 JDK를 사용하길 권장하고 있다.

인텔리제이 베타판 중에 JDK 최신(현재 8)을 포함해 배포하고 있는 버전이 있는 걸 보면, 애플이 JDK 버전을 올려주지 않아도 결국은 최신버전을 사용할 수 있게 될 것 같다.

 

참조

이클립스 워크스페이스 vs. 인텔리제이 프로젝트

이클립스(Eclipse) 개발자들이 인텔리제이(Intelli J)나 인텔리제이 기반의 안드로이드 스투디오(Android Studio)로 IDE를 옮기면서 처음에 만나는 불편함을 꼽으라면, 이클립스의 워크스페이스(workspace)가 인텔리제이에는 없다는 것일 듯 하다. 사실 인텔리제이에 이클립스의 워크스페이스에 상응하는 프로젝트라는 개념이 있지만 아래 두 가지 이유로 사람들이 눈치채기 어렵다.

  • 이클립스 워크스페이스를 인텔이제이에서 임포트할 때 워크스페이스 내의 한 프로젝트만 임포트 된다.
  • 프로젝트라는 개념이 이클립스에서는 워크스페이스 내의 소속되는 하위 개념인데 반해, 인텔리제이에서는 최상위 개념으로 그 하위에 하나 이상의 모듈을 포함할 수 있어 용어에서 혼란을 느낀다.

결론부터 말하면, 인텔리제이(나 안드로이드 스투디오)에서 이클립스의 워크스페이스(와 같은 구조)를 사용하고자 한다면 이클립스의 워크스페이스를 File > Import Project를 통해 바로 열면 된다.  위자드에서 몇가지 설정을 묻지만 Next만 눌러도 실행할 수 있도록 워크스페이스를 가져온다. 물론 File > Project Structure를 통해 살펴보면 중복된 라이브러리나 필요없는 설정 등이 있지만 실행에 문제는 없다.

또한 프로젝트 구조를 살펴봐도 아래처럼 이클립스 워크스페이스와 안드로이드 스투디오의 프로젝트 구조가 같다.

eclipse_workspace
workspace structure in Eclipse
intellij_project
project structure in Intelli J

위와 같은 구조를 잡은 후에는 이클립스의 워크스페이스 + 프로젝트과 동일하다고 생각하면 된다. 아래와 같이 모듈(이클립스의 프로젝트)별로 안드로이드 SDK나 keystore등을 지정할 수 있다.

project_structure
Project Structures in Android Studio

또한 Run/Debug configurations 창을 통해 모듈마다 실행 방법을 지정할 수도 있다.

run_configurations
Run/Debug Configurations in Android Studio

그 밖에

마지막으로, 인텔리제이와 이클립스에서 사용되는 용어는 인텔이제이의 마이그레이션 FAQ에 표로 설명되어 있는데, 이를 옮기면 아래와 같다.

Eclipse IDEA
Workspace Project
Project Module
Project-specific JRE Module JDK
User library Global library
Classpath variable Path variable
Project dependency Module dependency
Library Module library

 

참고

  • 마이그레이션 FAQ : https://www.jetbrains.com/idea/documentation/migration_faq.html
  • 이클립스 워크스페이스 임포트하기 : https://www.jetbrains.com/idea/webhelp/import-eclipse-workspace.html

인텔리제이 단축키

인텔리제이 단축키를 찾아 헤매는가? 인터넷에 많이 있지만, 그게 최신인지 변경되거나 늘어난 것은 없는지 알 수가 없다. 인텔리제이에서는 Help > Default Keymap Reference 메뉴를 통해 단축키 .pdf 파일을 바로 보여준다.

intellij_reference참조

  • http://www.jetbrains.com/idea/docs/IntelliJIDEA_ReferenceCard.pdf

 

13.1.4 com.google.common.io.Closeables.closeQuietly(Ljava/io/Closeable;)V

인텔리제이 커뮤니티 에디션을 13.1.3에서 13.1.4로 오늘 업데이트 했는데, 아래와 같은 문제가 생겼다.

Error:Internal error: (java.lang.NoSuchMethodError) com.google.common.io.Closeables.closeQuietly(Ljava/io/Closeable;)V
java.lang.NoSuchMethodError: com.google.common.io.Closeables.closeQuietly(Ljava/io/Closeable;)V
	at com.android.sdklib.internal.project.ProjectProperties.parsePropertyStream(ProjectProperties.java:541)
	at com.android.sdklib.repository.local.LocalAddonPkgInfo.parseAddonProperties(LocalAddonPkgInfo.java:370)
	at com.android.sdklib.repository.local.LocalAddonPkgInfo.createAndroidTarget(LocalAddonPkgInfo.java:199)
	at com.android.sdklib.repository.local.LocalPlatformPkgInfo.getAndroidTarget(LocalPlatformPkgInfo.java:95)
	at com.android.sdklib.repository.local.LocalAddonPkgInfo.getVendorId(LocalAddonPkgInfo.java:110)
	at com.android.sdklib.repository.local.LocalAddonPkgInfo$1.getVendorId(LocalAddonPkgInfo.java:96)
	at com.android.sdklib.repository.descriptors.PkgDescAddon.getVendorId(PkgDescAddon.java:93)
	at com.android.sdklib.repository.descriptors.PkgDesc.compareTo(PkgDesc.java:226)
	at com.android.sdklib.repository.descriptors.PkgDesc.compareTo(PkgDesc.java:42)
	at com.android.sdklib.repository.local.LocalPkgInfo.compareTo(LocalPkgInfo.java:126)
	at com.android.sdklib.repository.local.LocalPkgInfo.compareTo(LocalPkgInfo.java:40)
	at com.google.common.collect.NaturalOrdering.compare(NaturalOrdering.java:35)
	at com.google.common.collect.NaturalOrdering.compare(NaturalOrdering.java:26)
	at java.util.TreeMap.compare(TreeMap.java:1188)
	at java.util.TreeMap.put(TreeMap.java:531)
	at java.util.TreeSet.add(TreeSet.java:255)
	at com.google.common.collect.AbstractMapBasedMultimap$WrappedCollection.add(AbstractMapBasedMultimap.java:503)
	at com.android.sdklib.repository.local.LocalSdk.scanAddons(LocalSdk.java:916)
	at com.android.sdklib.repository.local.LocalSdk.getPkgsInfos(LocalSdk.java:566)
	at com.android.sdklib.repository.local.LocalSdk.getTargets(LocalSdk.java:694)
	at com.android.sdklib.repository.local.LocalSdk.getTargetFromHashString(LocalSdk.java:722)
	at org.jetbrains.jps.android.AndroidJpsUtil.getAndroidTarget(AndroidJpsUtil.java:375)
	at org.jetbrains.jps.android.AndroidJpsUtil.getAndroidPlatform(AndroidJpsUtil.java:448)
	at org.jetbrains.jps.android.builder.AndroidPreDexBuildTarget.computeRootDescriptors(AndroidPreDexBuildTarget.java:110)
	at org.jetbrains.jps.builders.impl.BuildRootIndexImpl.addRoots(BuildRootIndexImpl.java:72)
	at org.jetbrains.jps.builders.impl.BuildRootIndexImpl.<init>(BuildRootIndexImpl.java:62)
	at org.jetbrains.jps.cmdline.BuildRunner.load(BuildRunner.java:76)
	at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:198)
	at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:113)
	at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler$1.run(BuildMain.java:133)
	at org.jetbrains.jps.service.impl.SharedThreadPoolImpl$1.run(SharedThreadPoolImpl.java:41)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:744)

complie할 때 에러가 나는데 workspace를 다시 만들거나, SDK 업데이트, 설정 초기화 등 다 해봐도 해결이 안된다 -_- 다른 프로젝트를 열어도 모두 같은 문제가 생기는 걸 보면, 한 프로젝트에서 설정을 잘못한 것은 아닌거 같은데.. 아무래도 IDE 문제인 것 같다.

결국 인텔리제이 14 EAP(Early Access Program)로 업데이트하고 나서야 문제가 해결되었다. 모든 커뮤니티 에디션 사용자를 베타테스터로 몰기위한 전략인건가;