Tuesday, December 13, 2011

DrewGaren.com: Nexus S - ICY+ S version 1.0

기다리던 롬! 이제 플래싱 할시간!!

여러가지 롬들 사용해봤지만 Nexus S용 ICS롬은 DrewGaren ROM이 제일 맘에 든다.
구글 지원들이 Official ICS ROM 사용중이라고 하니 공식 릴리즈 되기 전까지는 큰 문제 없으면 이 롬에 정착 할 듯. <-- 플래싱 해보니.. 너무 문제가 많다. 다시 Beta ROM으로 복원 -_-;

DrewGaren.com: Nexus S - ICY+ S version 1.0: Nexus S Rom - ICY+ S version 1.0 The first stable release of Android 4.0.1 Ice Cream Sandwich from DrewGaren. Minus, fully enabled camera e...

Friday, December 9, 2011

Android C2DM client 예제


준비물 : c2dm account(파이썬으로 c2dm서버 만들기 포스팅 참조)

만들 예제의 패키지 구조

우선 Manifest file의 Code



    

    
        
            
                

                
            
        
        
        
  
   
   
    
    
   
   
   
    
    
   
  
  
    
 
 
 

 
 



중요한 부분:
15~ 28 line <-com.leehack.c2dmtest.push.C2DMReceiver 등록
31~36 line <- C2DM을 사용할 수 있도록 어플에 permission부여

C2DMReceiver.java: 리시버 작성

package com.leehack.c2dmtest.push;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;

public class C2DMReceiver extends BroadcastReceiver {
 static String registration_id = null;
 private Context mContext;
 @Override
 public void onReceive(Context context, Intent intent) {
  if (intent.getAction().equals(
    "com.google.android.c2dm.intent.REGISTRATION")) {
   handleRegistration(context, intent);
  } else if (intent.getAction().equals(
    "com.google.android.c2dm.intent.RECEIVE")) {
   handleMessage(context, intent);
  }
 }
 //서버에 등록이 되면 Registration_id를 C2DM서버에서 보내준다. 받은 이 ID를 별도로 구성한 서버에 보내야 한다.
 private void handleRegistration(Context context, Intent intent) {
  String registration = intent.getStringExtra("registration_id");
  if (intent.getStringExtra("error") != null) {
   // Registration failed, should try again later.
  } else if (intent.getStringExtra("unregistered") != null) {
   registration = null;
  } else if (registration != null) {
   registration_id = registration;
   mContext = context;
   SharedPreferences sp  = mContext.getSharedPreferences("com.leehack.c2dmtest", Activity.MODE_PRIVATE);
   SharedPreferences.Editor ed = sp.edit();
   ed.putString("registration_id", registration_id);
   ed.commit();
   Toast toast = Toast.makeText(context, "Registration Id\n" + registration_id,
     Toast.LENGTH_LONG);
   toast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 150);
   toast.show();
   Log.d("C2DMReceiver", "c2dm registered");
  }
 }
 //메세지가 도착하면 토스트로 도착한 메세지를 보여줌
 private void handleMessage(Context context, Intent intent) {

  String c2dm_msg = intent.getExtras().getString("msg");

  System.out.println("c2dm_msg======>" + c2dm_msg);
  Toast toast = Toast.makeText(context, "c2dmMessage\n" + c2dm_msg,
    Toast.LENGTH_LONG);
  toast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 150);
  toast.show();

 }
}

PushHelper.java: c2dm 서버에 Register/Unregister 메소드 작성

package com.leehack.c2dmtest.push;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;

public class PushHelper {

 final static String c2dmDevId = "c2dm에 등록한 account";
 
 public static void c2dmRegister(Context context){
  SharedPreferences sp  = context.getSharedPreferences("com.leehack.c2dmtest", Activity.MODE_PRIVATE);
  if(sp.getString("registration_id", null) != null)
   return;
  Intent registrationIntent = new Intent(
    "com.google.android.c2dm.intent.REGISTER");
  registrationIntent.putExtra("app",
    PendingIntent.getBroadcast(context, 0, new Intent(), 0));
  registrationIntent.putExtra("sender", c2dmDevId);
  context.startService(registrationIntent);
 }
 public static void c2dmUnregister(Context context){
  Intent unregIntent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
  unregIntent.putExtra("app", PendingIntent.getBroadcast(context, 0, new Intent(), 0));
  context.startService(unregIntent);
 }
}


C2DM_TESTActivity.java: Register와 Unregister버튼의 동작을 정의

package com.leehack.c2dmtest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;

import com.leehack.c2dmtest.push.PushHelper;

public class C2DM_TESTActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    PushHelper.c2dmRegister(C2DM_TESTActivity.this);
   }
  });
        findViewById(R.id.button2).setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    PushHelper.c2dmUnregister(C2DM_TESTActivity.this);
   }
  });
    }
}

앞으로 해야 할일!
1. 구글의 C2DM과 통신한 Push Server 구성
2. Register를 한 후 C2DMReceiver를 통해 C2DM 서버로 부터 전달받은 Registration_ID를 구성한 Push Server로 전달하는 로직 구성
(파이썬으로 c2dm서버 만들기 포스팅을 참조하면 1번은 해결될 것이고 2번만 추가로 구성하면 된다)

Python으로 c2dm server 만들기

1. http://code.google.com/intl/ko-KR/android/c2dm/ 에서 c2dm 서비스에 sign-up
(gmail account를 새로 만들어서 가입하는 것이 좋다. - 실제로 이 account정보를 클라이언트 및 서버에 모두 넣어야 하고 더구나 서버에는 패스워드정보도 필요하기 때문)

2. 가입하면 E-mail로 가입한 Account로 서비스가 Enable되었다는 내용의 메일이 옮(보통 하루안에 오고 늦어도 몇일 사이에는 오는 듯)

여기까지 준비 완료! 아래는 실제 파이썬 코드 시작!!

import urllib, urllib2

class ClientLoginTokenFactory(): 
    _token = None 
    
    def __init__(self):
        self.url = 'https://www.google.com/accounts/ClientLogin'
        self.accountType = 'GOOGLE'
        self.email = 'c2dm에 가입한 메일주소'
        self.password = 'c2dm에 가입한 메일주소의 패스워드'
        self.source = 'replstory-replstory-0'
        self.service = 'ac2dm'
    
    def getToken(self):    
        if self._token is None:
            
            # Build payload
            values = {'accountType' : self.accountType,
                      'Email' : self.email,
                      'Passwd' : self.password, 
                      'source' : self.source, 
                      'service' : self.service}
            
            # Build request
            data = urllib.urlencode(values)
            request = urllib2.Request(self.url, data)
            
            # Post
            response = urllib2.urlopen(request)
            responseAsString = response.read()
            
            # Format response
            responseAsList = responseAsString.split('\n')
            
            self._token = responseAsList[2].split('=')[1]
            
        return self._token
    
class C2DM():
    
    def __init__(self):
        self.url = 'https://android.apis.google.com/c2dm/send'
        self.clientAuth = None
        self.registrationId = None
        self.collapseKey = None
        self.data = {}
        
    def sendMessage(self):
        if self.registrationId == None or self.collapseKey == None:
            return False
        
        clientAuthFactory = ClientLoginTokenFactory()
        self.clientAuth = clientAuthFactory.getToken()
        
        # Build payload
        values = {'registration_id' : self.registrationId,
                  'collapse_key' : self.collapseKey}     
        
        # Loop over any data we want to send
        for k, v in self.data.iteritems():            
            values['data.' + k] = v
        
        # Build request
        headers = {'Authorization': 'GoogleLogin auth=' + self.clientAuth}        
        data = urllib.urlencode(values)
        request = urllib2.Request(self.url, data, headers)
        
        # Post
        try:
            response = urllib2.urlopen(request)
            responseAsString = response.read()
            
            return responseAsString
        except urllib2.HTTPError, e:
            print 'HTTPError ' + str(e)
            
            
sender = C2DM()
sender.registrationId = 'Android단말기에서 c2dm서버로 부터 받은 고유번호'
sender.collapseKey = 1
sender.data = {'msg':'test'}
response = sender.sendMessage()
print response

9,10,79 라인의 정보만 바꾸고 실행하면 c2dm등록된 단말기로 test라는 푸시 메세지가 날아간다.
http://blog.boxedice.com/2010/10/07/android-push-notifications-tutorial/ 에 있는 예제코드인데 제대로 돌지 않아서 약간의 수정만 했음.

이미 눈치 채셨겠지만 실제 사용시에는 78라인부터만 따로 가져가서 원하는 곳에 사용하면 된다. collapseKey를 1로 고정해두고 사용하면 c2dm메세지가 동일한 단말에 동일한 메세지를 계속 적으로 보낼 경우 중간중간 빼먹는 경우가 생긴다. 구글에서 중복된 메세지 전송을 방지하게 넣어둔 코드임. 중복으로 보내는 메세지라도 단말에 꼭 전송이 되어야 하는 메세지라면 collapseKey를 increase하면서 보내는 것이 상책!

Thursday, December 8, 2011

Pydev에서 Library 인식 안될 때

여러가지 파이썬용 웹프레임웍을 이클립스의 Pydev에서 돌려보는 중 아주 눈에 거슬리는 것을 발견!!
빌드도 잘되고 Run도 잘되는데 저 빨간줄! 엑스표! 에디터상에 나타나는거 아주 짜증스럽다!

오늘은 맘먹고 고치겠다고 선언! 아무리 웹을 뒤져도 나오지 않는다! 왜일까... 결국엔 삽질 끝에 아주 간단히 해결.. eclipse->preference->interpreter -Python


위 화면에서 Auto Config click하면 이런화면이 나온다.

보통은 위에 선택되어 있는 것처럼 해놓고 사용했었는데.. (easy_install하면 젤 아래 /Library/Python/2.7/site-packages 에 들어가기 때문에..)
알고보니 library로 인식이 안되고 있는 것이였다 -_-;;(이런 멍청한! 모르면 죽어야지!)

Select All한 후 코드를 다시 열어보니.. 깔끔하게 보인다.


짠!

끝!!!

Wednesday, December 7, 2011

Python:: flask, webpy, Django, Bottle, web2py ...

Python으로 Web 개발 공부를 해보는 중.. 아무런 정보도 맨토도 없이 무작정 Django책부터 하나 붙잡고 시작. 100% 끝낸건 아니지만 일단 기본적인 정보는 모두 캐냈다고 판단 후 책을 덮음.

이제부터 현실적인 문제에 봉착. Django가 짱!인줄 알았는데.. 파이썬에는 수많은 좋은 웹프레임웍들이 존재한다는 것!

Bottle로 짠 Simple한 REST API예제를 보고 1차 감탄!

Web2Py 깔고서 관리자 페이지에서 IDE까지 제공해주는 Detail에 2차 감탄!

마지막으로 webpy까지 보고 나니 점점 헷갈린다!

Django가 잘 만들어진 녀석이긴 하지만 일단 다른 프래임웍들을 알아보다 보니 Python위에서 만들어진 기술이란 느낌 보다는 그냥 Django다! 라는 생각이 들었다.

Web2Py는 정말 제공해주는 것도 많고 편리하지만.. 어쩌면 개발자보다는 관리자 프랜들리한 느낌이 들어 좀 끄적여 보다가 패스!

webpy는 뭔가 내가 원하는 대로 자유롭게 사용할 수 있으면서도 심플하고 편리함을 모두 가지고 있어 맘에 들었고 이제 이것으로 결정! 하는 순간 Flask 라는 녀석이 눈에 들어왔다.

아직 자세히는 보지 못했지만..
Bottle스러운 심플함과 Django스러운 template engine(동일한 엔진을 plugin으로 붙여쓰는 듯..)을 가지고 있을 뿐만 아니라 webpy스러운 자유로움을 모두 가지고 있는 것 같다.

Flask라는 녀석이 마지막 방황이 되길 바라며..

Monday, December 5, 2011

유동 IP 사용하는 개인서버에 유료 도메인 세팅

결론부터 이야기 하자면 DNSEVER.COM 이라는 아주 고마운 서비스를 이용하면 DYNDNS.com 같은 Dynamic DNS 서비스를 개인 도메인에 붙여서 사용이 가능하다는 이야기!

*간단 요약
1. DNSEVER.COM 가입
2. DNSEVER에 도메인 추가.
3. 좌측 하단의 name server를 각 domain업체 홈페이지에서 변경
4. 다이나믹DNS 등록
5. Auto Refresh 설정

아래 링크에 가면 아주 친절하세 설명해주신 포스팅이 있다.

위 포스팅은 Windows base로 Refresh설명을 해주셨지만 아래 공식사이트에 가면 Linux용 설정방법도 있음.


*주의: Name server를 변경했기 때문에 향후 도메인 관리는 모두 DNSEVER에서 해야함. 유료화 계획이 없는 무료서비스임에도 불구하고 꽤 오래된 서비스이며 안정성도 어느정도 보장이 되어있으나 역시나 무료서비스에 Name Server를 맡기는 만큼 신중을 기해야 하는 것도 사실.

MAC에서 SSH Key 생성


1. SSH key가 있는지 확인
$cd ~/.ssh

2. 기존키 백업
$mkdir key_backup
$cp id_rsa* keybackup
$rm id_rsa*

3. ssh key 생성하기
$ssh-keygen -t rsa -C "이메일 주소"
Generating public/private rsa key pair.
Enter file in which to save the key
(/Users/사용자폴더/.ssh/id_rsa):엔터!
Enter passphrase (empty for no passphrase:패스워드!
Enter same passphrase again: 한번더!

*GitHub 사용법에서 퍼옴
http://help.github.com/mac-set-up-git/

Sunday, December 4, 2011

DrewGaren.com: Nexus S Beta 3 Coming Soon!

요즘 한참 쓰고 있는 DrewGaren의 Nexus S용 ICS ROM. Beta2사용중인데 Beta3가 나온다고 한다. 공식REL도 되기전에 이미 충분히 안정적이고 쓸만한 ROM을 생산해내고 있는 해커들.. 경이롭기까지 하다.

DrewGaren.com: Nexus S Beta 3 Coming Soon!: Beta 3 Ice Cream Sandwich for Nexus S Is Coming Soon, How About A Preview... You guys have been asking for some fixes and I'm going to get ...

PostgreSQL 9.1.1 + phpPgAdmin 설치

Ubuntu 11.10에서 PostgreSQL 9.1.1 + phpPgAdmin 설치하기

1. apt-get을 이용하여 Install하면 9.1.1이 자동으로 설치된다.
$sudo apt-get install postgresql

2. apt-get을 이용하여 phpPgAdmin 설치
$sudo apt-get install phpPgAdmin

3. 기본적으로 postgreSQL은 인증방식이 peer로 잡혀있다. password base로 접속하기 위해서는 trust로 변경을 해야한다.
$sudo vim /etc/postgresql/9.1/main/pg_hba.conf

가장 아랫쪽에 인증방식 설정하는 곳을 찾아 아래처럼 변경한다.
local    all    all                        trust
host    all    all    0.0.0.0/0    trust

*참고로 host의 address를 0.0.0.0/0 으로 설정한 것은 원격지에서 접속이 가능하도록 하기위해서다.

4. 원격지에서 접속 가능하도록 설정
$sudo vim /etc/postgresql/9.1/main/postgresql.conf

listen_addresses을 찾아 주석을 제거하고
listen_addresses = '*' 로 수정한다.

5. PostgreSQL 재시작
$sudo /etc/init.d/postgresql restart

6. User 추가하기
$sudo -u postgres createuser -P 'account name'

* -P 옵션은 계정을 추가하면서 password를 지정할 것이라는 옵션.

7. phpPgAdmin 원격접속 허용
$sudo vim /etc/phppgadmin/apache.conf

아래 두라인을 주석처리
deny from all
allow from 127.0.0.0/255.0.0.0 ::1/28

allow from all 추가

8. Apache 재시작
$sudo /etc/init.d/apache2 restart


여기까지 하면 세팅 완료. 6번에서 User추가시 super user를 추가했다면 앞으로는 http://localhost/phppgadmin 에서 user및 db 추가가 가능함.