首页 > 代码库 > 微信核心功能全解析

微信核心功能全解析

最近做了一套及时通讯软件,其中很多功能和微信是相仿的,下面详细介绍一下具体实现。

做及时通讯肯定要用xmpp协议,微信和一些及时通讯软件也是用的这套协议,只是纵向开发深度不同。

1.复写语音按钮

@SuppressLint("NewApi")
public class RecordButton extends Button  {
public RecordButton(Context context) {
super(context);
init();
}
public RecordButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public RecordButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void setSavePath(String path) {
mFileName = path;
}
public void setOnFinishedRecordListener(OnFinishedRecordListener listener) {
finishedListener = listener;
}
private String mFileName = null;
private OnFinishedRecordListener finishedListener;
private static final int MIN_INTERVAL_TIME = 2000;// 2s
private long startTime;
/**
* 取消语音发送
*/
private Dialog recordIndicator;
private static int[] res = { R.drawable.mic_2, R.drawable.mic_3,
R.drawable.mic_4, R.drawable.mic_5 };

private static ImageView view;
private MediaRecorder recorder;
private ObtainDecibelThread thread;
private Handler volumeHandler;
public final static int   MAX_TIME =60;//一分钟
private void init() {
volumeHandler = new ShowVolumeHandler();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mFileName == null)
return false;
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
setText("松开发送");
initDialogAndStartRecord();
break;
case MotionEvent.ACTION_UP:
this.setText("按住录音");
finishRecord();
break;
case MotionEvent.ACTION_CANCEL:// 当手指移动到view外面,会cancel
cancelRecord();
Toast.makeText(getContext(), "cancel", 1).show();
break;
}
return true;
}
private void initDialogAndStartRecord() {
startTime = System.currentTimeMillis();
recordIndicator = new Dialog(getContext(),
R.style.like_toast_dialog_style);
view = new ImageView(getContext());
view.setImageResource(R.drawable.mic_2);
recordIndicator.setContentView(view, new LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
recordIndicator.setOnDismissListener(onDismiss);
LayoutParams lp = recordIndicator.getWindow().getAttributes();
lp.gravity = Gravity.CENTER;
startRecording();
recordIndicator.show();
}
private void finishRecord() {
stopRecording();
recordIndicator.dismiss();
long intervalTime = System.currentTimeMillis() - startTime;
if (intervalTime < MIN_INTERVAL_TIME) {
Toast.makeText(getContext(), "时间太短!", Toast.LENGTH_SHORT).show();
File file = new File(mFileName);
file.delete();
return;
}
if (finishedListener != null)
finishedListener.onFinishedRecord(mFileName,(int) (intervalTime/1000));
}
private void cancelRecord() {
stopRecording();
recordIndicator.dismiss();
Toast.makeText(getContext(), "取消录音!", Toast.LENGTH_SHORT).show();
File file = new File(mFileName);
file.delete();
}
private void startRecording() {
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setAudioChannels(1);
recorder.setAudioEncodingBitRate(4000);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//recorder.setVideoFrameRate(4000);
recorder.setOutputFile(mFileName);
try {
recorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start();
thread = new ObtainDecibelThread();
thread.start();
}
private void stopRecording() {
if (thread != null) {
thread.exit();
thread = null;
}
if (recorder != null) {
recorder.stop();
recorder.release();
recorder = null;
}
}
private class ObtainDecibelThread extends Thread {
private volatile boolean running = true;
public void exit() {
running = false;
}
@Override
public void run() {
while (running) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (recorder == null || !running) {
break;
}
int x = recorder.getMaxAmplitude();
if (x != 0) {
int f = (int) (10 * Math.log(x) / Math.log(10));
if (f < 26)
volumeHandler.sendEmptyMessage(0);
else if (f < 32)
volumeHandler.sendEmptyMessage(1);
else if (f < 38)
volumeHandler.sendEmptyMessage(2);
else
volumeHandler.sendEmptyMessage(3);
}
}
}
}
private OnDismissListener onDismiss = new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
stopRecording();
}
};
static class ShowVolumeHandler extends Handler {
@Override
public void handleMessage(Message msg) {
view.setImageResource(res[msg.what]);
}
}
public interface OnFinishedRecordListener {
public void onFinishedRecord(String audioPath,int time);
}
//private  boolean 
}

2.文字,语音,文件发送接收


public class ChatActivity extends Activity {
private String userChat = "";// 当前聊天 userChat
private String userChatSendFile = "";// 给谁发文件
private ChatListAdapter adapter;
private List<Msg> listMsg = new LinkedList<Msg>();
private String pUSERID;// 自己的user
private String pFRIENDID;// 窗口的 名称
private EditText msgText;
private TextView chat_name;
private NotificationManager mNotificationManager;
private ChatManager cm;
private RecordButton mRecordButton;
// 发送文件
private OutgoingFileTransfer sendTransfer;
public static String FILE_ROOT_PATH = Environment
.getExternalStorageDirectory().getPath() + "/chat/file";
public static String RECORD_ROOT_PATH = Environment
.getExternalStorageDirectory().getPath() + "/chat/record";
Chat newchat;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.chat_client);
init();
mRecordButton = (RecordButton) findViewById(R.id.record_button);
String path = RECORD_ROOT_PATH;
File file = new File(path);
file.mkdirs();
path += "/" + System.currentTimeMillis() + ".amr";
mRecordButton.setSavePath(path);
mRecordButton
.setOnFinishedRecordListener(new OnFinishedRecordListener() {
@Override
public void onFinishedRecord(String audioPath, int time) {
Log.i("RECORD!!!", "finished!!!!!!!!!! save to "
+ audioPath);
if (audioPath != null) {
try {
// 自己显示消息
Msg myChatMsg = new Msg(pUSERID, time + "”语音消息",
TimeRender.getDate(), Msg.FROM_TYPE[1],
Msg.TYPE[0], Msg.STATUS[3], time + "",
audioPath);
listMsg.add(myChatMsg);
String[] pathStrings = audioPath.split("/"); // 文件名
//发送 对方的消息
String fileName = null ;
if (pathStrings!=null && pathStrings.length>0) {
fileName = pathStrings[pathStrings.length-1];
}
Msg sendChatMsg = new Msg(pUSERID, time + "”语音消息",
TimeRender.getDate(), Msg.FROM_TYPE[0],
Msg.TYPE[0], Msg.STATUS[3], time + "",
fileName);
// 刷新适配器
adapter.notifyDataSetChanged();
// 发送消息
newchat.sendMessage(Msg.toJson(sendChatMsg));
sendFile(audioPath, myChatMsg);//
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toast.makeText(ChatActivity.this, "发送失败",
Toast.LENGTH_SHORT).show();
}
}
});
}
private void init() {
mNotificationManager = (NotificationManager) this
.getSystemService(Service.NOTIFICATION_SERVICE);
// 获取Intent传过来的用户名
this.pUSERID = getIntent().getStringExtra("USERID");
this.userChat = getIntent().getStringExtra("user");/*
userChatSendFile = userChat + "/" + FriendListActivity.MY_RESOUCE_NAME;
this.pFRIENDID = getIntent().getStringExtra("FRIENDID");
chat_name = (TextView) findViewById(R.id.chat_name);
chat_name.setText(pFRIENDID);
ListView listview = (ListView) findViewById(R.id.formclient_listview);
listview.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
this.adapter = new ChatListAdapter(this, listMsg);
listview.setAdapter(adapter);
// 获取文本信息
this.msgText = (EditText) findViewById(R.id.formclient_text);
// 消息监听
cm = XmppConnection.getConnection().getChatManager();
// 返回按钮
Button mBtnBack = (Button) findViewById(R.id.chat_back);
mBtnBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
finish();
}
});
receivedMsg();// 接收消息
sendMsg();// 发送消息
receivedFile();// 接收文件
}

/**
* 接收消息
*/
public void receivedMsg() {
cm.addChatListener(new ChatManagerListener() {
@Override
public void chatCreated(Chat chat, boolean able) {
chat.addMessageListener(new MessageListener() {
@Override
public void processMessage(Chat chat2, Message message) {
// 收到来自pc服务器的消息(获取自己好友发来的信息)
if (message.getFrom().contains(userChat)) {
// Msg.analyseMsgBody(message.getBody(),userChat);
// 获取用户、消息、时间、IN
// 在handler里取出来显示消息
android.os.Message msg = handler.obtainMessage();
System.out.println("服务器发来的消息是 chat:"
+ message.getBody());
msg.what = 1;
msg.obj = message.getBody();
msg.sendToTarget();
}
}
});
}
});
}
/**
* 发送消息

* @author Administrator

*/
public void sendMsg() {
// 发送消息
Button btsend = (Button) findViewById(R.id.formclient_btsend);
// 发送消息给pc服务器的好友(获取自己的服务器,和好友)
newchat = cm.createChat(userChat, null);
btsend.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 获取text文本
final String msg = msgText.getText().toString();
if (msg.length() > 0) {
// 自己显示消息
Msg chatMsg = new Msg(pUSERID, msg, TimeRender.getDate(),
Msg.FROM_TYPE[1]);
  listMsg.add(chatMsg);
  //发送对方
  Msg sendChatMsg = new Msg(pUSERID, msg, TimeRender.getDate(),
Msg.FROM_TYPE[0]); 
// 刷新适配器
adapter.notifyDataSetChanged();
try {
// 发送消息
newchat.sendMessage(Msg.toJson(sendChatMsg));
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toast.makeText(ChatActivity.this, "发送信息不能为空",
Toast.LENGTH_SHORT).show();
}
// 清空text
msgText.setText("");
}
});
}
/**
* 接收文件

* @author Administrator

*/
public void receivedFile() {
/**
* 接收文件
*/
// Create the file transfer manager
final FileTransferManager manager = new FileTransferManager(
XmppConnection.getConnection());
// Create the listener
manager.addFileTransferListener(new FileTransferListener() {
public void fileTransferRequest(FileTransferRequest request) {
// Check to see if the request should be accepted
Log.d("receivedFile ", " receive file");
if (shouldAccept(request)) {
// Accept it
IncomingFileTransfer transfer = request.accept();
try {
System.out.println(request.getFileName());
File file = new File(RECORD_ROOT_PATH
+ request.getFileName());

android.os.Message msg = handler.obtainMessage();
transfer.recieveFile(file);
Msg msgInfo = queryMsgForListMsg(file.getName());
msgInfo.setFilePath(file.getPath());//更新 filepath
new MyFileStatusThread(transfer, msgInfo).start();
} catch (XMPPException e) {
e.printStackTrace();
}
} else {
// Reject it
request.reject();
String[] args = new String[] { userChat,
request.getFileName(), TimeRender.getDate(), "IN",
Msg.TYPE[0], Msg.STATUS[1] };
Msg msgInfo = new Msg(args[0], "redio", args[2], args[3],
Msg.TYPE[0], Msg.STATUS[1]);
// 在handler里取出来显示消息
android.os.Message msg = handler.obtainMessage();
msg.what = 5;
msg.obj = msgInfo;
handler.sendMessage(msg);
}
}
});
}
/**
* 发送文件

* @param path
*/
public void sendFile(String path, Msg msg) {
/**
* 发送文件
*/
// Create the file transfer manager
FileTransferManager sendFilemanager = new FileTransferManager(
XmppConnection.getConnection());
// Create the outgoing file transfer
sendTransfer = sendFilemanager
.createOutgoingFileTransfer(userChatSendFile);
// Send the file
try {
sendTransfer.sendFile(new java.io.File(path), "send file");
new MyFileStatusThread(sendTransfer, msg).start();
/**
* 监听
*/
} catch (XMPPException e) {
e.printStackTrace();
}
}
class MyFileStatusThread extends Thread {
private FileTransfer transfer;
private Msg msg;
public MyFileStatusThread(FileTransfer tf, Msg msg) {
transfer = tf;
this.msg = msg;
}
public void run() {
System.out.println(transfer.getStatus());
System.out.println(transfer.getProgress());
android.os.Message message = new android.os.Message();// handle
message.what = 3;
while (!transfer.isDone()) {
System.out.println(transfer.getStatus());
System.out.println(transfer.getProgress());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (transfer.getStatus().equals(Status.error)) {
msg.setReceive(Msg.STATUS[2]);
} else if (transfer.getStatus().equals(Status.refused)) {
msg.setReceive(Msg.STATUS[1]);
} else {
msg.setReceive(Msg.STATUS[0]);// 成功
}
handler.sendMessage(message);
/*
* System.out.println(transfer.getStatus());
* System.out.println(transfer.getProgress());
*/
}
}
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
Msg chatMsg = Msg.analyseMsgBody(msg.obj.toString());
if (chatMsg != null) {
listMsg.add(chatMsg);// 添加到聊天消息
adapter.notifyDataSetChanged();
}
break;
case 2: // 发送文件
break;
case 3: // 更新文件发送状态
adapter.notifyDataSetChanged();
break;
case 5: // 接收文件
Msg msg2 = (Msg) msg.obj;
System.out.println(msg2.getFrom());
listMsg.add(msg2);
adapter.notifyDataSetChanged();
default:
break;
}
};
};
@Override
public void onBackPressed() {
super.onBackPressed();
// XmppConnection.closeConnection();
System.exit(0);
}
protected void setNotiType(int iconId, String s) {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent appIntent = PendingIntent.getActivity(this, 0, intent, 0);
Notification myNoti = new Notification();
myNoti.icon = iconId;
myNoti.tickerText = s;
myNoti.defaults = Notification.DEFAULT_SOUND;
myNoti.flags |= Notification.FLAG_AUTO_CANCEL;
myNoti.setLatestEventInfo(this, "QQ消息", s, appIntent);
mNotificationManager.notify(0, myNoti);
}
/**
* 是否接收

* @param request
* @return
*/
private boolean shouldAccept(FileTransferRequest request) {
final boolean isAccept[] = new boolean[1];
return true;
}
protected void dialog() {
}
/**
* init file
*/
static {
File root = new File(FILE_ROOT_PATH);
root.mkdirs();// 没有根目录创建根目录
root = new File(RECORD_ROOT_PATH);
root.mkdirs();
}
/**
* 从list 中取出 分拣名称相同的 Msg
*/
private Msg queryMsgForListMsg(String filePath){
Msg msg = null;
for (int i = listMsg.size()-1; i>=0; i--) {
msg = listMsg.get(i);
if (filePath!=null && filePath.contains(msg.getFilePath()) ) {// 对方传过来的只是文件的名称
return msg;
}
}
return msg;
}
}

如需整个项目的留下邮箱地址。

转载注明出处。