org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:395)
org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:349)
Once you get tired of the limitations of android’s built-in IMProvider and the corresponding API – IXmppSession and IXmppService, try the sample below. Inside the source/binary zip (bottom of this article) you will find a smack.jar that works with android. To build the jar yourself, You can download the Smack 3.0.4 sources from here and apply the patch here.
01 |
package org.apache.android.xmpp; |
02 |
03 |
import android.app.Dialog; |
04 |
import android.util.Log; |
05 |
import android.view.View; |
06 |
import android.widget.Button; |
07 |
import android.widget.EditText; |
08 |
import org.jivesoftware.smack.ConnectionConfiguration; |
09 |
import org.jivesoftware.smack.XMPPConnection; |
10 |
import org.jivesoftware.smack.XMPPException; |
11 |
import org.jivesoftware.smack.packet.Presence; |
12 |
13 |
/** |
14 |
* Gather the xmpp settings and create an XMPPConnection |
15 |
*/ |
16 |
public class SettingsDialog extends Dialog implements android.view.View.OnClickListener { |
17 |
private XMPPClient xmppClient; |
18 |
19 |
public SettingsDialog(XMPPClient xmppClient) { |
20 |
super (xmppClient); |
21 |
this .xmppClient = xmppClient; |
22 |
} |
23 |
24 |
protected void onStart() { |
25 |
super .onStart(); |
26 |
setContentView(R.layout.settings); |
27 |
getWindow().setFlags( 4 , 4 ); |
28 |
setTitle( "XMPP Settings" ); |
29 |
Button ok = (Button) findViewById(R.id.ok); |
30 |
ok.setOnClickListener( this ); |
31 |
} |
32 |
33 |
public void onClick(View v) { |
34 |
String host = getText(R.id.host); |
35 |
String port = getText(R.id.port); |
36 |
String service = getText(R.id.service); |
37 |
String username = getText(R.id.userid); |
38 |
String password = getText(R.id.password); |
39 |
40 |
// Create a connection |
41 |
ConnectionConfiguration connConfig = |
42 |
new ConnectionConfiguration(host, Integer.parseInt(port), service); |
43 |
XMPPConnection connection = new XMPPConnection(connConfig); |
44 |
45 |
try { |
46 |
connection.connect(); |
47 |
Log.i( "XMPPClient" , "[SettingsDialog] Connected to " + connection.getHost()); |
48 |
} catch (XMPPException ex) { |
49 |
Log.e( "XMPPClient" , "[SettingsDialog] Failed to connect to " + connection.getHost()); |
50 |
xmppClient.setConnection( null ); |
51 |
} |
52 |
try { |
53 |
connection.login(username, password); |
54 |
Log.i( "XMPPClient" , "Logged in as " + connection.getUser()); |
55 |
56 |
// Set the status to available |
57 |
Presence presence = new Presence(Presence.Type.available); |
58 |
connection.sendPacket(presence); |
59 |
xmppClient.setConnection(connection); |
60 |
} catch (XMPPException ex) { |
61 |
Log.e( "XMPPClient" , "[SettingsDialog] Failed to log in as " + username); |
62 |
xmppClient.setConnection( null ); |
63 |
} |
64 |
dismiss(); |
65 |
} |
66 |
67 |
private String getText( int id) { |
68 |
EditText widget = (EditText) this .findViewById(id); |
69 |
return widget.getText().toString(); |
70 |
} |
71 |
} |
001 |
package org.apache.android.xmpp; |
002 |
003 |
import android.app.Activity; |
004 |
import android.os.Bundle; |
005 |
import android.os.Handler; |
006 |
import android.util.Log; |
007 |
import android.view.View; |
008 |
import android.widget.ArrayAdapter; |
009 |
import android.widget.Button; |
010 |
import android.widget.EditText; |
011 |
import android.widget.ListView; |
012 |
import org.jivesoftware.smack.PacketListener; |
013 |
import org.jivesoftware.smack.XMPPConnection; |
014 |
import org.jivesoftware.smack.filter.MessageTypeFilter; |
015 |
import org.jivesoftware.smack.filter.PacketFilter; |
016 |
import org.jivesoftware.smack.packet.Message; |
017 |
import org.jivesoftware.smack.packet.Packet; |
018 |
import org.jivesoftware.smack.util.StringUtils; |
019 |
020 |
import java.util.ArrayList; |
021 |
022 |
public class XMPPClient extends Activity { |
023 |
024 |
private ArrayList<String> messages = new ArrayList(); |
025 |
private Handler mHandler = new Handler(); |
026 |
private SettingsDialog mDialog; |
027 |
private EditText mRecipient; |
028 |
private EditText mSendText; |
029 |
private ListView mList; |
030 |
private XMPPConnection connection; |
031 |
032 |
/** |
033 |
* Called with the activity is first created. |
034 |
*/ |
035 |
@Override |
036 |
public void onCreate(Bundle icicle) { |
037 |
super .onCreate(icicle); |
038 |
setContentView(R.layout.main); |
039 |
040 |
mRecipient = (EditText) this .findViewById(R.id.recipient); |
041 |
mSendText = (EditText) this .findViewById(R.id.sendText); |
042 |
mList = (ListView) this .findViewById(R.id.listMessages); |
043 |
setListAdapter(); |
044 |
045 |
// Dialog for getting the xmpp settings |
046 |
mDialog = new SettingsDialog( this ); |
047 |
048 |
// Set a listener to show the settings dialog |
049 |
Button setup = (Button) this .findViewById(R.id.setup); |
050 |
setup.setOnClickListener( new View.OnClickListener() { |
051 |
public void onClick(View view) { |
052 |
mHandler.post( new Runnable() { |
053 |
public void run() { |
054 |
mDialog.show(); |
055 |
} |
056 |
}); |
057 |
} |
058 |
}); |
059 |
060 |
// Set a listener to send a chat text message |
061 |
Button send = (Button) this .findViewById(R.id.send); |
062 |
send.setOnClickListener( new View.OnClickListener() { |
063 |
public void onClick(View view) { |
064 |
String to = mRecipient.getText().toString(); |
065 |
String text = mSendText.getText().toString(); |
066 |
067 |
Log.i( "XMPPClient" , "Sending text [" + text + "] to [" + to + "]" ); |
068 |
Message msg = new Message(to, Message.Type.chat); |
069 |
msg.setBody(text); |
070 |
connection.sendPacket(msg); |
071 |
messages.add(connection.getUser() + ":" ); |
072 |
messages.add(text); |
073 |
setListAdapter(); |
074 |
} |
075 |
}); |
076 |
} |
077 |
078 |
/** |
079 |
* Called by Settings dialog when a connection is establised with the XMPP server |
080 |
* |
081 |
* @param connection |
082 |
*/ |
083 |
public void setConnection |
084 |
(XMPPConnection |
085 |
connection) { |
086 |
this .connection = connection; |
087 |
if (connection != null ) { |
088 |
// Add a packet listener to get messages sent to us |
089 |
PacketFilter filter = new MessageTypeFilter(Message.Type.chat); |
090 |
connection.addPacketListener( new PacketListener() { |
091 |
public void processPacket(Packet packet) { |
092 |
Message message = (Message) packet; |
093 |
if (message.getBody() != null ) { |
094 |
String fromName = StringUtils.parseBareAddress(message.getFrom()); |
095 |
Log.i( "XMPPClient" , "Got text [" + message.getBody() + "] from [" + fromName + "]" ); |
096 |
messages.add(fromName + ":" ); |
097 |
messages.add(message.getBody()); |
098 |
// Add the incoming message to the list view |
099 |
mHandler.post( new Runnable() { |
100 |
public void run() { |
101 |
setListAdapter(); |
102 |
} |
103 |
}); |
104 |
} |
105 |
} |
106 |
}, filter); |
107 |
} |
108 |
} |
109 |
110 |
private void setListAdapter |
111 |
() { |
112 |
ArrayAdapter<String> adapter = new ArrayAdapter<String>( this , |
113 |
R.layout.multi_line_list_item, |
114 |
messages); |
115 |
mList.setAdapter(adapter); |
116 |
} |
117 |
} |
-dontskipnonpubliclibraryclassmembers
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontpreverify
-verbose
# keep option들..
# keep옵션이란 난독화시 난독화를 하지 않아야 하는 코드들을 미리 지정하는 것으로
# 안드로이드 jar파일이나 프로젝트의 경우 아래의 keep옵션들이 필요할 것입니다.
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembers,allowshrinking class * {
public <init>(android.content.Context,android.util.AttributeSet);
}
-keepclasseswithmembers,allowshrinking class * {
public <init>(android.content.Context,android.util.AttributeSet,int);
}
# Also keep - Enumerations. Keep the special static methods that are required in
# enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Keep names - Native method names. Keep all native class/method names.
-keepclasseswithmembers,allowshrinking class * {
native <methods>;
}
위 옵션들과 함께 입력파일과 출력파일을 지정하고 참조하고 있는 라이브러리까지 지정하는 스크립트 코드는 아래와 같습니다.
# 난독화를 진행할 입력 파일명
-injars myjar.jar
# 난독화를 거친 출력 파일명
-outjars out_myjar.jar
# 입력파일이 참조하는 라이브러리들...
# 안드로이드용 jar라면 android.jar를 반드시 포함해야 할것이다.
# 그 외에 혹시 추가로 참조하는 라이브러리가 있다면 추가해 주어야 한다.
-libraryjars /Users/yosamlee/Desktop/android-sdk-mac_x86/platforms/android-7/android.jar
-libraryjars /Users/yosamlee/_TOOL/workspace/MyJar/lib/referencelib.jar
위의 스크립트를 모두 모아서 확장자 *.pro로 저장한다.
proguard설치 폴더로 가서 bin폴더의 proguardgui를 실행한다. 아래와 같은 커맨드라인 명령을 콘솔에서 입력하면 됩니다.
java -jar ../lib/proguardgui.jar
위 화면에서 "Load configuration ..."을 선택 후 앞서 저장해 둔 스크립트파일을 오픈합니다
스크립트 파일이 성공적으로 열렸다면 Process tab에서 "Process!"버튼을 선택하면 난독화 과정을 거칩니다.
...
Number of branch peephole optimizations: 0
Number of simplified instructions: 0
Number of removed instructions: 0
Number of removed local variables: 0
Number of removed exception blocks: 0
Number of optimized local variable frames: 0
Shrinking...
Removing unused program classes and class elements...
Original number of program classes: 26
Final number of program classes: 26
Obfuscating...
Writing output...
Preparing output jar [/Users/yosamlee/_TOOL/workspace/MyJar/bin/out_myjar.jar]
Copying resources from program jar [/Users/yosamlee/_TOOL/workspace/MyJar/bin/myjar.jar]
Processing completed successfully
정상적으로 과정이 진행되었다면 위와 같은 성공하였다는 메세지를 보게 될것입니다.
이제 out_myjar.jar파일을 리버스엔지니어링 해보길 바랍니다.
원하는 만큼 난독화가 진행되었는지 말이죠~!
만족할 만한 결과가 나왔기를 바랍니다.
ps) 이미 느끼신 분들도 계시겠지만 위 과정은 proguardgui버전에서 그대로 수행이 가능합니다. 저는 왜 수동으로 스크립트를 만들었냐면요.... 옵션들이 하도 많아서 헤깔려서요. GUI버전이 편하신 분들은 그걸 사용하셔도 됩니다.
Keyboard | OS function |
---|---|
Escape | Back button |
Home | Home button |
F2, PageUp | Menu (Soft-Left) button |
Shift-F2, PageDown | Star (Soft-Right) button |
F3 | Call/Dial button |
F4 | Hangup/EndCall button |
F5 | Search button |
F7 | Power button |
Ctrl-F3, Ctrl-KEYPAD_5 | Camera button |
Ctrl-F5, KEYPAD_PLUS | Volume up button |
Ctrl-F6, KEYPAD_MINUS | Volume down button |
KEYPAD_5 | DPad center |
KEYPAD_4 | DPad left |
KEYPAD_6 | DPad right |
KEYPAD_8 | DPad up |
KEYPAD_2 | DPad down |
Keyboard | Emulator function |
---|---|
F8 | toggle cell network on/off |
F9 | toggle code profiling (when -trace option set) |
Alt-ENTER | toggle fullscreen mode |
Ctrl-T | toggle trackball mode |
Ctrl-F11, KEYPAD_7 | switch to previous layout |
Ctrl-F12, KEYPAD_9 | switch to next layout |
KEYPAD_MULTIPLY | increase onion alpha |
KEYPAD_DIVIDE | decrease onion alpha |
For a detailed view of API changes in Android 2.0.1 (API Level 6), as compared to API Level 5, see the API Differences Report. Note that this difference report compares only to the most recent API Level, and there are few changes, so to see changes introduces in Android 2.0 (API Level 5), see the API Differences between 4 and 5.