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버전이 편하신 분들은 그걸 사용하셔도 됩니다.