2012년 9월 27일 목요일

Javascript 정규 표현식


정규 표현식(Regular Expression) 이란?

문자열에서 특정한 캐릭터 조합(character combination)을 찾아내기위한 패턴(pattern)입니다.
특정 문자나 문자열로 문자열을 다루는 것에 문자뿐 만이 아니고 특수 문자로 다룰 수 있고 이들을 조합하여 다룰 수 있는 조건식(pattern)을 제공하여 더 세밀한 방법으로 문자들을 검색할 수 있게 합니다.
정규 표현식(Regular Expression) 생성 방법
1. object initializers를 사용한 방법
정규표현 =/패턴설정/[i/g/gi]var re = /ab+c/i
2. RegExp 객체의 constructor function를 사용한 방법
new RegExp("패턴 설정"[, "i", | ,"g", | "gi"])var re = new RegExp("ab+c", "i")
정규 표현식(Regular Expression) 플래그 구성 요소(생략 가능)
g완전일치(발생할 모든 pattern에 대한 전역 검색)
i대/소문자 무시
gi대/소문자 무시하고 완전 일치

정규 표현식(Regular Expression) 과 함께 사용하는 함수들
MethodType설명
exec()RegExp문장에서 매치를 위해 검색을 수행하는 정규 표현식 메소드
배열을 리턴
지정된 패턴과 같은 패턴을 찾는다.
test()RegExp문장에서 매치를 위해 테스트하는 정규표현식 메소드
True 또는 False 리턴
같은 패턴이 있는지 테스트 한다.
match()String문장에서 매치를 위해 검색을 수행하는 string 메소드
배열 또는 null 문자 리턴
지정된 패턴과 동일한 패턴을 찾는다.
search()String문장에서 매치를 위해 테스트하는 string 메소드
목차나 -1 리턴
첫번째로 일치하는 부분 문자열의 위치를 반환합니다
replace()String문장에서 매치를 위해 검색을 실행 문장을 대체하는 String 메소드
지정된 패턴과 바꾼다.
split()String문장에서 매치하는 부분을 배열에 할당하는 String 메소드
지정된 패턴부분에서 문자열을 나눈다.

정규 표현식에서 사용하는 특수문자
문자설명
다음에 나오는 특수 문자를 문자열로 인식
예 : \' 시퀀스는 ""를 찾고 '/'는 "/"를 찾습니다.
^입력 문자열의 시작 위치를 찾습니다.(라인의 처음과 패턴과 찾습니다.)
가령, ^A 라고 써주면 검색하고자 하는 문장의 시작문자가 A인지를 검사하는 것입니다.
$입력 문자열의 끝 위치를 찾습니다.(라인의 끝과 패턴과 찾습니다.)
가령, $A 라고 써주면 검색하고자 하는 문장의 마지막문자가 A인지를 검사하는 것입니다.
*0개 이상의 문자와 찾습니다.( 모든것이라는 의미 ==> {0,} 같은 의미 )
예 : "cg*"는 "c", "cginjs" 등입니다.
+1개 이상의 문자와 찾습니다.( {1,} 같은 의미임. )
예 : "cg+"는 "cg", "cginjs" 등이지만 "c"는 아닙니다.
?0 또는 1개의 문자 의미.( {0,1} 같은 의미임. )
예 : " C?j" 라면 C라는 문자와 j라는 문자사이에 문자가 0개 또는 1개 가 들어갈 수 있다는 말입니다.
      Cj, Cnj, Cgj등과 같은..
."n"을 제외한 모든 단일 문자를 찾습니다.
"n"을 포함한 모든 문자를 찾으려면 '[.n]' 패턴을 사용하십시오.
()한번 match를 수행해서 나온 결과를 기억함.
예 : /(cnj)/ 는 cnj라는 단어를 검색한 후, 그 단어를 배열등과 같은 저장장소에 남겨두어 나중에 다시 호출할 수 있도록 합니다.
|OR
{n}정확히 n개의 문자(n은 음이 아닌 정수)
예: a{2} 는 a 문자 두 개, 즉, aa를 의미합니다.
{n,}n정확히 n개 찾습니다.(n,음이 아닌 정수)
예 : "c{2}"는 "cnj"의 "c"는 찾지 않지만 "bcccccccccf"의 모든 c는 찾습니다.
{n,m}최소 n개, 최대 m개 찾습니다.(n은 음이 아닌 정수)
예 : "b{1,4}"은 "bcccccccccf"의 처음 네 개의 c를 찾습니다.
쉼표와 숫자 사이에는 공백을 넣을 수 없습니다.
[xyz]괄호 안의 문자 중 하나를 찾습니다.(문자들의 set를 의미)
가령, [a-z]라면 a부터 z까지의 모든 문자와 찾습니다.하는 것으로 []안의 -는 범위를 나타냅니다.
괄호 안의 문자 중 하나를 찾습니다.
예:, "[abc]"는 "cnj"의 "c"를 찾습니다.
[^xyz]제외 문자 집합입니다.(네가티브(-) 캐릭터 셋)
괄호 밖의 문자 중 하나를 찾습니다.
예 : "[^abc]"는 "acn"의 "n"를 찾습니다.
x|yx 또는 y를 찾습니다.
예 : "c|cginjs"는 "c" 또는 "cginjs"를 찾습니다.
[a-z]문자 범위입니다.(지정한 범위 안의 문자를 찾습니다)
예 : "[a-z]"는 "a"부터 "z" 사이의 모든 소문자를 찾습니다.
[^a-z]제외 문자 범위입니다(지정된 범위 밖의 문자를 찾습니다)
예 : "[^a-z]"는 "a"부터 "z" 사이에 없는 모든 문자를 찾습니다.
[b]백스페이스와 찾습니다.
b단어와 공백 사이의 위치를 찾습니다.(단어의 경계)
예 : "erb"는 "never"의 "er"는 찾지만 "verb"의 "er"는 찾지 않습니다.
B단어의 비경계를 찾습니다.
예 : "erB"는 "verb"의 "er"는 찾지만 "never"의 "er"는 찾지 않습니다.
cXX 가 나타내는 제어 문자를 찾습니다.(control 문자와 찾습니다)
예 : cM은 Control-M 즉, 캐리지 리턴 문자를 찾습니다.
      x 값은 A-Z 또는 a-z의 범위 안에 있어야 합니다.
      그렇지 않으면 c는 리터럴 "c" 문자로 간주됩니다.
d0부터 9까지의 아라비아 숫자와 찾습니다.. [0-9]과 같은 의미
D비숫자 문자를 찾습니다. [^0-9]와 같습니다.
f폼피드 문자(form-feed)를 찾습니다.(x0c와 cL과 같은 의미)
nlinefeed(줄 바꿈 문자)를 찾습니다.(x0a와 cJ과 같은 의미)
r캐리지 리턴 문자를 찾습니다(x0d와 cM과 같은 의미)
s공백, 탭, 폼피드 등의 공백을 찾습니다.( [ tnrfv]과 같은 의미)
Ss가 아닌 문자(공백이 아닌 문자)를 찾습니다. ( [^ tnrfv]과 같은 의미)
t탭 문자를 찾습니다. (x09와 cI와 같은 의미)
v수직 탭 문자를 찾습니다.(x0b와 cK와 같은 의미)
w밑줄을 포함한 모든 단어 문자를 찾습니다.( "[A-Za-z0-9_]"와 같은 의미)
W문자가 아닌 요소,
즉 % 등과 같은 특수 문자를 의미함( "[^A-Za-z0-9_]"와 같은 의미)
nn은 마지막 일치하는 문장
xnn을 찾습니다. 여기서 n은 16진수 이스케이프 값입니다.
16진수 이스케이프 값은 정확히 두 자리여야 합니다.
예 : 'x41'은 "A"를 찾고 'x041'은 'x04'와 "1"과 같습니다.
       정규식에서 ASCII 코드를 사용할 수 있습니다.
numnum을 찾습니다.(num은 양의 정수)
캡처한 문자열에 대한 역참조입니다.
예 : '(.)1'은 연속적으로 나오는 동일한 문자 두 개를 찾습니다.
nm8진수 이스케이프 값이나 역참조를 나타냅니다.
nm 앞에 최소한 nm개의 캡처된 부분식이 나왔다면 nm은 역참조입니다.
nm 앞에 최소한 n개의 캡처가 나왔다면 n은 역참조이고 뒤에는 리터럴 m이 옵니다.
이 두 경우가 아닐 때 n과 m이 0에서 7 사이의 8진수이면 nm은 8진수 이스케이프 값 nm을 찾습니다.
nmln이 0에서 3 사이의 8진수이고 m과 l이 0에서 7 사이의 8진수면 8진수 이스케이프 값 nml을 찾습니다.
unn은 4 자리의 16진수로 표현된 유니코드 문자입니다.
예 : u00A9는 저작권 기호(ⓒ)를 찾습니다.
ooctal
xhex
8(octal)진수, 10(hex)진수 값

정규 표현식에서 사용하는 property
속성설명
global완전 일치
ignoreCase대문자 소문자 무시
lastIndex다음 패턴조회를 시작하는 위치
source조회시킬 패턴
input검색 문자열의 설정, 변경($_로도 가능)
multiline줄바구기 코드를 무시할지 여부($_로도 가능)
참(무시하지 않는다), 거짓(무시한다.)로 설정
lastMatch패턴 조회한 최후의 문자($&로도 가능)
lastParen패턴 조회한 최후의 substring($+로도 가능)
leftContext패턴 조회한 값의 앞의 문자($¥Q로도 가능)
rightContext패턴 조회한 값의 다음 문자($'로도 가능)
$1~$9패턴 조회한 것의 일부를 저장한다.(9개까지

정규 표현식(Regular Expression) 사용예제 1
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // 'c' 가 있는 문자열이 있으면 TRUE (대/소문자 구분)
  5. var cnj_re = /c/
  6. var cnj_ment = "'c' 가 있는 문자열이 있으면 TRUE (대/소문자 구분)nn변수 : " + cnj_re;
  7. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  8. alert(cnj_ment + "nn문자열이 있군요(true)");
  9. } else {
  10. alert(cnj_ment + "nn문자열이 없군요(fail)");
  11. }
  12. }
  13. //-->
  14. </SCRIPT>
  15. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()">

정규 표현식(Regular Expression) 사용예제 2
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // 'CGINJS' 가 있는 문자열이 있으면 TRUE (대/소문자 구분)
  5. var cnj_re = /CGINJS/
  6. var cnj_ment = "'CGINJS' 가 있는 문자열이 있으면 TRUE (대/소문자 구분)nn변수 : " + cnj_re;
  7. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  8. alert(cnj_ment + "nn문자열이 있군요(true)");
  9. } else {
  10. alert(cnj_ment + "nn문자열이 없군요(fail)");
  11. }
  12. }
  13. //-->
  14. </SCRIPT>
  15. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()"> 


정규 표현식(Regular Expression) 사용예제 3
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // 대소문자 구분없이 해당 문자 또는 문자열을 검색할 경우 끝에 i 를 붙인다.
  5. // 'cginjs' 또는'CGINJS' 가 있는 문자열 모두가 있으면 TRUE (대/소문자 구분)
  6. var cnj_re = /CGINJS/i
  7. var cnj_ment = "'cginjs' 또는 'CGINJS' 가 있는 문자열 모두가 있으면 TRUE (대/소문자 구분)nn변수 : " + cnj_re;
  8. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  9. alert(cnj_ment + "nn문자열이 있군요(true)");
  10. } else {
  11. alert(cnj_ment + "nn문자열이 없군요(fail)");
  12. }
  13. }
  14. //-->
  15. </SCRIPT>
  16. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()"> 

정규 표현식(Regular Expression) 사용예제 4
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // 여러개의 이어지는 내용들을 검색할 경우는 '-' 를 넣어 표현한다.
  5. // 'a' 에서 'z' 까지중 하나만 있으면 모두가 TRUE (대소문자 구분)
  6. var cnj_re = /[a-z]/
  7. var cnj_ment = "'a' 에서 'z' 까지중 하나만 있으면 모두가 TRUE (대소문자 구분)nn변수 : " + cnj_re;
  8. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  9. alert(cnj_ment + "nn문자열이 있군요(true)");
  10. } else {
  11. alert(cnj_ment + "nn문자열이 없군요(fail)");
  12. }
  13. }
  14. //-->
  15. </SCRIPT>
  16. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()">

정규 표현식(Regular Expression) 사용예제 5
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // | 는 OR 같은 의미
  5. // 여러가지의 문자 또는 문자열을 검색할 경우 '|' 이용
  6. // 'x' 또는 'y' 또는 'z' 가 있는 문자열 모두가 TRUE (대소문자 구분)
  7. var cnj_re = /x|y|z/
  8. var cnj_ment = "'x' 또는 'y' 또는 'z' 가 있는 문자열 모두가 TRUE (대소문자 구분)nn변수 : " + cnj_re;
  9. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  10. alert(cnj_ment + "nn문자열이 있군요(true)");
  11. } else {
  12. alert(cnj_ment + "nn문자열이 없군요(fail)");
  13. }
  14. }
  15. //-->
  16. </SCRIPT>
  17. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()"> 

정규 표현식(Regular Expression) 사용예제 6
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // | 는 OR 같은 의미
  5. // 여러가지의 문자 또는 문자열을 검색할 경우 '|' 이용
  6. // 'a' 에서 'z' 까지 또는 '0' 에서 '9' 까지중 하나만 있으면 모두가 TRUE (대소문자 구분)
  7. var cnj_re = /[a-z]|[0-9]/
  8. var cnj_ment = "'a' 에서 'z' 까지 또는 '0' 에서 '9' 까지중 하나만 있으면 모두가 TRUE (대소문자 구분)nn변수 : " + cnj_re;
  9. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  10. alert(cnj_ment + "nn문자열이 있군요(true)");
  11. } else {
  12. alert(cnj_ment + "nn문자열이 없군요(fail)");
  13. }
  14. }
  15. //-->
  16. </SCRIPT>
  17. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()">

정규 표현식(Regular Expression) 사용예제 7
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // 해당 문자또는 문자열이 없는 경우를 검색할 경우 브래킷('[', ']') 안에 '^' 를 넣는다.
  5. // 'a' 에서 'z' 까지의 문자가 아닌 문자가 있을 경우 TRUE (대소문자 구분)
  6. var cnj_re = /[^a-z]/
  7. var cnj_ment = "'a' 에서 'z' 까지의 문자가 아닌 문자가 있을 경우 TRUE (대소문자 구분)nn변수 : " + cnj_re;
  8. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  9. alert(cnj_ment + "nn문자열이 있군요(true)");
  10. } else {
  11. alert(cnj_ment + "nn문자열이 없군요(fail)");
  12. }
  13. }
  14. //-->
  15. </SCRIPT>
  16. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()"> 

정규 표현식(Regular Expression) 사용예제 8
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // 문자열의 첫번째 글자가 일치해야할 경우는 '^' 를 브래킷('[', ']') 밖에 넣는다
  5. // 'a' 에서 'z' 까지의 문자로 시작하는 문자열일 겨우 TRUE (대소문자 구분)
  6. var cnj_re = /^[a-z]/
  7. var cnj_ment = "'a' 에서 'z' 까지의 문자로 시작하는 문자열일 겨우 TRUE (대소문자 구분)nn변수 : " + cnj_re;
  8. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  9. alert(cnj_ment + "nn문자열이 있군요(true)");
  10. } else {
  11. alert(cnj_ment + "nn문자열이 없군요(fail)");
  12. }
  13. }
  14. //-->
  15. </SCRIPT>
  16. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()">

정규 표현식(Regular Expression) 사용예제 9
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // 문자열의 끝쪽 글자가 해당 문자 또는 문자열과 일치해야할 경우는 '$' 를 넣는다.
  5. // 'a' 에서 'z' 까지의 문자로 끝나는 문자열일 겨우 TRUE (대소문자 구분)
  6. var cnj_re = /[a-z]$/
  7. var cnj_ment = "'a' 에서 'z' 까지의 문자로 끝나는 문자열일 겨우 TRUE (대소문자 구분)nn변수 : " + cnj_re;
  8. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  9. alert(cnj_ment + "nn문자열이 있군요(true)");
  10. } else {
  11. alert(cnj_ment + "nn문자열이 없군요(fail)");
  12. }
  13. }
  14. //-->
  15. </SCRIPT>
  16. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()">

 정규 표현식(Regular Expression) 사용예제 10
  1. <SCRIPT LANGUAGE="JavaScript">
  2. <!--
  3. function cnj_regexp() {
  4. // 특수문자('', '^', '$', '*', '+', '?', '.', '(', ')', '|', '{', '}', '[', ']')를 검색할 경우는 '' 를 넣는다.
  5. // '' 가 있는 문자열일 겨우 TRUE (대소문자 구분)
  6. var cnj_re = /\/
  7. var cnj_ment = "'' 가 있는 문자열일 겨우 TRUE (대소문자 구분)nn변수 : " + cnj_re;
  8. if (cnj_re.test("When Cgi Met Javascript = CginJs.Com") == true) {
  9. alert(cnj_ment + "nn문자열이 있군요(true)");
  10. } else {
  11. alert(cnj_ment + "nn문자열이 없군요(fail)");
  12. }
  13. }
  14. //-->
  15. </SCRIPT>
  16. <input type="button" name="cnj_text" value="확인" omClick="cnj_regexp()"> 

2012년 9월 19일 수요일

안드로이드 디컴파일 방지 방법


Android How to use Proguard in the Eclipse
이글은 http://developer.android.com/guide/developing/tools/proguard.html 의 내용을 기반으로 작성되었습니다.


 프로가드는 널리 사용되고 있는 코드 난독화 툴로, 여러분의 어플리케이션을 크래커의 공격으로 부터 보다 안전하게 보호하고 동시에, 코드 사이즈를 줄여주며, 그리고 약간의 최적화도 곁들여 주는 아주 아주 훌륭한 오프소스 툴입니다. 프로가드는 GPL 라이센스를 갖는 도구로 해당 코드를 수정하거나 툴 자체를 재배포할 수는 없지만, 공개된 프로가드를 이용하여 여러분의 어플리케이션을 난독화 하는데에는 어떠 제약 조건 없이 사용하실 수 있습니다. 구글 팀은 LVL 라이브러리를 공개 하고,  라인센싱 서비스를 시작한 직 후 부터, 코드 난독화 툴 - 특히 프로가드 툴을 사용할 것을 권장했으며, 마침내 새롭게 등장한 진저브레드 버전 부터는 아예 ADT 단에서 프로가드 사용을 지원하고 있습니다. 따라서, 개발자분들은 새롭게 업데이트된 ADT 를 사용하는 한, 꼭 2.3 타겟의 어플리케이션을 만드는 경우가 아니더라도 정말로 손쉽게 프로가드 툴을 사용하실 수 있습니다. 그 방법에 관하여, 구글 개발자 가이드 문서에 나온 내용을 기반으로 간단하게 그 사용법을 정리해 보았습니다.

프로가드 사용하기

 우선 당연히 현재 사용하고 계신 ADT 를 최신 버전(8.0.1 이 후 버전)을 설치 하셔야합니다. 기존에 설치된 ADT 가 있으시면 최신 버전으로 업데이트 하시면 됩니다. ADT 를 업데이트 하는 것과, 어플리케이션 타겟 플랫폼을 결정하는 것은 별다른 상관이 없으니 호환성에 대하여 큰 걱정 하지 않고 과감하게 업데이트 하셔도 좋습니다.


 ADT 업데이트를 마친 후에, 새로운 안드로이드 프로젝트를 만드시면, 프로젝트 루트 폴더에 기존과 다른 proguard.cfg 라는 파일이 생성되는 것을 확인 하실 수 있습니다. 프로가드 환경 설정 파일이라고 생각하시면 되며, 기본적으로 안드로이드에 알맞은 설정 값(메니페스트에서 이름으로 참조하는 클래스는 난독화 하지 않는 등,...)을 갖고 있음으로, 개인 개발자 분들이라면 별다른 수정 없이 해당 설정 파일을 사용하시면 될 듯 합니다. 
그리고 마지막으로, 프로젝트 루트 폴더의 default.properties (프로젝트 설정 파일이조) 파일을 열어서 아래와 같이 프로가드를 사용하겠다고 설정 값을 추가하시면 됩니다.  
proguard.config=proguard.cfg
 네...이게 전부입니다. 이 상황에서 여러분이 릴리즈 버전으로 어플리케이션을 익스포트 하시면, 빌드과정에서 자동으로 프로가드 툴이 동작합니다. 정말 쉬어졌습니다. 만세~! 그리고, 프로가드 툴이 정상적으로 동작하고 나면, 여러분의 프로젝트 폴더에 proguard 라는 하위 폴더가 새롭게 생성되며 해당 폴더 내에, 다음의 네 가지 파일이 생성됩니다. 

  • dump.txt : 여러분의 어플리케이션에서 사용중인 클래스들의 내부 구조에 대한 대략적인 정보를 나타냅니다. 말그대로 난독화 하기 위해 소스를 분석하는 과정에서 나오는 덤프값들이겠조. 뭐. 
  • mapping.txt : 이 파일은 중요합니다. 난독화 과정에서 기존 클래스 혹은 메서드가 어떤 새로운 난독화된 이름으로 매핑되었는지 그 목록을 표시해 줍니다. 난독화 된 어플리케이션에 발생하는 로그나, 스택 트레이스 들을 분석하기 위해서 꼭 챙겨 두셔야 합니다.
  • seeds.txt : 난독화 되지 않은 클래스와 멤버들의 목록입니다.
  • usage.txt : 사용되지 않기 때문에, apk 파일에서 제거된 코드들의 목록입니다. 혹시 제거되서는 안되는 메서드나 클래스가 제거되었는지 꼭 확인해 봐야 합니다.

프로가드 설정 하기

 왠만한 경우에는 구글에서 기본적으로 설정한 proguard.cfg 가 잘 동작하겠지만, 몇몇 경우 프로가드 툴이 난독화 과정에서 잘못된 클래스나 멤버를 난독화 하거나 실재로는 사용되는 메서드를 제거하는 등의 오류를 일으킬 수 도 있습니다. 예를 들자면,

  • 실제 코드가 아니라 AndroidManifest.xml 파일 내에서만 참조되는 클래스
  • JNI 형식으로만 호출되는 메서드
  • 동적으로 참조되는 필드 값이나 메스드들 

 프로가드 툴을 적용한 후 어플리케이션을 실행시켰을 때, ClassNotFoundException 등의 예외가 발생한다면 위의 경우를 의심해 봐야 합니다. 이처럼 프로가드 툴이 건들지 말아야할 코드를 건들여서 문제가 발생하는 것을 방지하기 위해, proguard.cfg 파일을 열어, -keep 항목을 추가로 선언할 수 있습니다.
-keep public class <MyClass>
 -keep 속성과 함께 사용할 수 있는 다양한 옵션 값들이 있습니다. 이에 관한 보다 상세한 내용은 프로가드 메뉴얼 문서를 직접 참조하시면 좋을 것 같습니다. 

난독화된 어플리케이션을 디버깅 하기

 난독화된 어플리케이션의 스택 트레이스 정보는 엉망 진창이 되기 쉽상입니다. 온갖 메서드 이름과 클래스 이름이 전부 난독화되었을테니 말입니다. 디버깅이 불가능한 것은 아니지만, 결코 쉬운 일은 아닐테조. 하지만 앞서 이야기 한 것 처럼, 난독화 과정에서 생성되는 mapping.txt 파일에 원본 이름이 어떻게 변경되었는지에 관한 내용이 저장됩니다. 프로가드 툴과 함께 제공되는 retrace.bat 혹은 retrace.sh 스크립트는 바로 이 mapping.txt 파일의 내용을 기반으로 난독화된 스택 트레이스 정보를 자동으로 변환시켜 줍니다. <sdk_root>/tools/proguard/ 디렉토리에 위치하며 다음과 같이 사용하시면 됩니다.
retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]
For example:
retrace.bat -verbose mapping.txt obfuscated_trace.txt
출시한 어플리케이션 디버깅 하기

 한가지 주의 점이 있습니다. 난독화 과정에서 생성되는 mapping.txt 파일은 기존 파일을 덮어 쓰게되어있습니다. 따라서, 개발자분들은 릴리즈 버전에 해당하는 mapping.txt 파일을 주의깊게 보존하셔야 합니다. 만일 그렇지 않을경우, 사용자들이 어플리케이션 사용주에 발생하는 크래쉬나 ANR 문제들에 관한 귀중한 정보를 보내온다 하더라도, 해당 내용을 해석할 수 없어서 발을 동동 구르게 될지도 모릅니다.

2012년 9월 12일 수요일

WBS에 대하여


# WBS (Work Breakdown Structures)란?
여기서는 프로젝트 관리의 측면이 아니라 각 멤버가 프로젝트에 있어서 자신의 작업목표를 관리하는 데에 WBS를 어떻게 활용할 것인가를 생각해 보기로 한다.
WBS는 한마디로 말하면 프로젝트 목적달성에 필요한 작업을 정의하기 위한 툴이라 할 수 있다.
다음의 4스텝을 거쳐서 작성한다.

1. 프로젝트의 목적을 정한다.
2. 프로젝트에서 작성할 프로덕트, 서비스, 결과 등의 성과물을 구체적으로 정한다.
3. 요소 성과물이나 중간 성과물, 전체 성과물에 공통적인 작업항목을 빠짐없이 정한다.
4. 2와 3의 항목을 분해해서 계획 및 컨트롤에 적절한 볼륨이 될 때까지 계속 분해한다.
4의 결과 분해된 최후의 항목을 워크패키지라고 부른다.

여기서 포인트는 WBS의 각 요소는 명사와 수식어로 표현한다는 것이다.
워크패키지까지 분해하고 나면 그 다음에는 워크패키지를 액티비티라고 하는 작업레벨로 분해한다. 액티비티는 [~을 수행한다]란 표현이 되도록 한다.

작성한 WBS는 요원조달, 예산작성, 스코프 설명 등 프로젝트의 여러 방면에 사용되며, 멤버의 역할과 책임은 워크패키지 또는 액티비티 단위로 주어진다.
이처럼 WBS는 프로젝트의 전체상을 나타내는 지도의 역할을 한다.

# WBS (Work Breakdown Structures)의 작성 방법
프로젝트 전체의 WBS는 프로젝트 관리팀에서 작성하며 각 멤버가 직접 관여하는 일은 많지 않다.
그리고, 작성된 WBS에 의해 멤버에게 역할과 책임이 주어지면 작업을 실행하게 된다. 즉, 개개의 멤버는 워크패키지 또는 액티비티로 구체화 되어진 후에 비로서 WBS와 관계를 갖게 된다. 그리하여 워크패키지나 액티비티의 수행에 책임을 지니게 되는 것이다.

통상적으로 WBS에서는 다음과 같은 요소 성과물을 고려해서 분해/구체화한다.
1. 프로덕트를 분해
2. 서비스를 분해
3. 프로젝트 결과를 분해
4. 프로젝트 전체의 횡단적 요소
5. 프로젝트 매니지먼트 요소

그러나, 멤버에게 있어서는 분해/구체화의 기준이나 그 레벨보다는 구체화된 WBS항목(워크패키지)의 구체적인 내용이 더욱 중요하다. 이 내용을 WBS사전이라 부른다.
즉, 프로젝트 전체의 WBS를 작성하는 것 그 자체보다는 담당부분의 WBS와 전체와의 정합성을 맞추어서 작성하는 것이 멤버력향상을 위해서는 보다 더 중요하다는 것이다.

# WBS 사전에 쓸 항목
WBS사전에 어떤 항목이 필요한지는 프로젝트의 종류나 성격에 따라 다르긴 하나 최소한 다음의 항목은 필요하다.
1. WBS 항목 번호
2. WBS 항목 명칭
3. WBS 항목의 내용
4. 필요한 액티비티 (작업내용)
5. 작업에 필요한 성과물
6. 견적 공수
7. 개시 예정일과 완료 예정일
8. 담당자명
9. 예상되는 리스크

그리고, 프로젝트에 있어서 멤버가 책임을 갖는다는 것은 담당하는 WBS 항목에 대하여 요구되어지는 성과를 주어진 시간내에 달성한다는 것이다. 즉, 담당 작업에 대하여 커밋한다는 것을 의미한다.

이를 위해서도 담당할 작업의 WBS 부분을 작성하는 것은 커밋이 보다 원할하게 이루어질 수 있으며, 이것은 담당부분의 WBS 작성에 멤버가 참여함으로써 얻을 수 있는 잇점이라 할 수 있을 것이다.


성과를 달성을 위한 각 멤버의 셀프 매니지먼트에 대하여 기술한다.

프로젝트에 있어 멤버가 성과를 달성한다고 하는 것은 담당 작업에 요구되는 성과를 주어진 시간 안에 확실히 달성하는 것이다. 이를 위해서는 다음의 사항을 고려하여 작업을 수행해야 한다.

1. 시간의 사용법
2. 작업의 효율화
3. 현상을 정확하게 보고하기
4. 확실한 달성을 위하여 자신의 작업에 숨어 있는 리스크에 대한 관리

WBS 사전에는 작성할 성과물, 필요한 작업, 견적공수, 개시 예정일과 완료 예정일 이 기재되어 있다. 그것을 바탕으로 위 1~3을 고려하여 자신이 수행해야 할 작업을 breakdown한다.

그것은 먼저 작업의 우선순위를 고려한다는 것이며, 하지 않아도 되는 작업은 하지 않는 것이다.
일반적으로 중요한 작업이 무엇인가를 생각하여 우선순위를 매기는 작업에 착수하도록 한다.
그 "중요한 작업"을 판단하는 과정에서 '여지껏 계속 해왔으니까'라든가 '나중의 작업이 편하니까'라는 등의 습관처럼 행하고 있는 일이 포함되는 경우가 꽤 있으리라 본다.

일단 자기가 올려야 할 성과를 올리기 위해서 이 작업이 과연 필요한가라는 자문을 해봅시다.

여지껏 중요하다고 생각했던 작업이라도 '성과달성에 필요한가'라는 자문의 결과 필요없다고 판단되면 과감히 버릴 필요가 있다.

이제부터는 WBS사전의 내용 중에서 자기가 해야 할 작업을 breakdown함에 있어서 습관적으로 하고 있던 작업에 대하여 정말로 필요한 작업인가를 자문해보기로 하자.

또한, 효율적인 작업이 되기 위해서는 시간관리를 통하여 집중하는 것이 중요하다. 여기서 시간관리라 함은 '집중할 수 있는 시간'을 말하는 것으로 1시간~2시간이 적당하다. 이 시간동안에 할 작업을 정하여, 이 정해진 시간에 작업을 완료하였나 여부데 "작은 성공, 달성감을 얻는 것"에서부터 작업의 효율화를 꾀해보도록 하자.

그리하여 일정시간에 수행한 작업의 완료여부를 모아서 현황보고를 한다.


또한, WBS항목 중의 「예상가능한 리스크」에 대해서는 리스크를 항상 고려하도록 하자.
그리하여 리스크에 민감해지고 리스크발생을 가능한한 신속히 파악하여, 팀장 및 프로젝트 매니저에게 보고 / 의논 / 대처함으로써 위의 3, 4번을 실현할 수 있다.

보고를 함에 있어서 각 멤버는 반드시 리스크에 대한 대처방법을 생각해두도록 한다.
또한, 리스크 계획 및 리스크 대처방법이 정해져 있다면 그 대처방법에 의한 리스크의 해소도나 영향도를 추정해두자.
각각의 멤버는 리스크 발생 현장에 가장 가까이 위치하므로 리스크에 관한 정보를 가장 많이 확보할 수 있는 것이다.
그 정보화 현장 담당자로서의 판단을 보고하고 의논하므로써 보다 신속하고 질 높은 리스크 대처가 가능하다.

이를 위해서는 담당작업에 있어 예상되는 리스크는 무엇인가? 그것을 신속히 파악하기 위해서는 무엇에 주의해야 하는가 등을 이해해 둘 필요가 있다.

위의 내용들을 각 멤버가 고려함으로써 보다 나은 작업성과를 달성할 수 있을 것이다.

2012년 9월 3일 월요일

앱 Proguard 적용하기


안드로이드 apk파일을 추출하여 디컴파일을 하게되면 거의 모든 소스를 볼수가 있었다.(모 저도 앱 참조할때 디컴파일 사용해서 해보기 했지만;;;)

이것을 방지하기 위한 proguard를 적용하기로 했다. 프로가드를 적용하여 소스를 보호하자.

구글을 android proguard를 검색하게 되면 많이 나오지만 기본적인 프로가드 적용방법이라... 정말로 필요한 부분만 정리하는 것이 좋을같아 정리를 해야겠다고 생각을 했다~

안드로이드 프로젝트를 생성하게 되면 proguard.cfgproject.properties 파일이 있다.


인디고에서는  project.properties 갈릴레오버전에서는 default.properties로 생성될것이다.



빨간색 밑줄 쓴 부분만 project.properties파일에 입력한다음 apk파일을 export하면 일단 성공이다.
proguard.config=proguard.cfg

이과정은 구글 검색에서 많이 나오는 부분이라 .. 두가지의 예외가 생겼었는데 하나는 proguard jar파일을 access못한다는 에러였고 또하나는 waring jar파일의 패키지명이 나온예러였다.(정확히는 생각이...)

첫번째 proguard의 jar파일을 access어쩌구저쩌구 에러가 나오게 된다면
안드로이드의 sdk가 설치된 폴더로 가서 나같은 경우는(C:\Android\sdk\tools\proguard\bin)
tools-> proguard ->bin 폴더에 있는 proguard파일을 메모장이나 edit plus와 같은 편집기를 열어

맨밑에 설정된 부분을 
call %java_exe% -jar "%PROGUARD_HOME%"\lib\proguard.jar %1 %2 %3 %4 %5 %6 %7 %8 %9
위와 같은 식으로 설정해 준다. jar %1사이의 띄어쓰기는 매우중요함..

이렇게 해도 안된다고하면 proguardgui, retrace파일까지 열어서 위의 문장이 제대로 입력되어있는지 확인하여야한다.
(저같은 경우는 3가지 파일중 하나가 jar와 %1부분이 띄어쓰기가 안되어 있어 에러가 계속;;;)

 
 (에러가 계속난다면 꼭3개의 파일을 열어 확인을..)

두번째는 Waring jar어쩌구저쩌구가 나는 에러다.
이것은 외부 Jar파일을 사용하지 않을때는 거의 안날것이다. 나같은 경우 viewpager와 navermap을 사용하기 위해 nmaps.jar, android-support-v4.jar 파일을 사용했는데 아무런 수정없이 apk를 export하게 된다면 반드시 에러가 날것이다.(아마도 내 생각에는 이미 프로가드가 적용되서 그런것 같은데 확실히는 몰르겠다)

위 두jar파일에 대해서는 proguard를 적용하지 않는다는 문구가 필요했다.


위의 그림 처럼 저렇게 nmaps.jar, android-support-v4.jar에 대한 패키지명을 지정하면 두 jar파일은 proguard를 적용시키지 않는다.
그럼 성공적으로 apk파일에 proguard가 적용될것이다.

-dontwarn android.support.v4.**
-dontwarn com.nhn.android.maps.**

p.s 만약 다른 jar를 사용하고 있다면 에러문구에 나오는 패키지부분을  -dontwarn 다음에 써주면될것 같다.
ex) warning com.hyo.itte.class, warning com.hyo.zzz.class 가 나왔다면 -dontwarn   com.hyo.**이렇게 입력하면 될것이다(공통부분만 찾아서 나머지는 **)

proguad가 적용이 잘되었다면



위와 같이 proguard폴더에 4개의 파일생성되었다면 성공한것이다. 처음 apk를 생성할때는 바로 확인이 안될수도 있다.(너무 걱정안해도 된다. 에러만 안나온다면 )
이클립스를 종료해서 다시 들어오게 된다면 생성되어 있을것이고 아님 프로젝트 폴더가 저장된 부분에 가면 확인할 수 있다. (만약 생성이 안되어 있다면 적용실패;;)

정말로 확인을 위해서는 프로가드를 적용하지 않은 apk파일과 적용한 후의 apk파일을 똑같이 디컴파일하게되면 확실히 알 수가 있다. 디컴파일 부분은 다음시간에 정리할 것이다.

출처 : http://hyojoong2-dev.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9CProguard-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0