微信核心功能全解析

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

做及时通讯肯定要用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;

}

}

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

转载注明出处。

微信核心功能全解析,布布扣,bubuko.com

时间: 2024-08-11 09:45:27

微信核心功能全解析的相关文章

《在WebView中如何让JS与Java安全地互相调用》核心JS全解析

1.说明: <[在WebView中如何让JS与Java安全地互相调用](http://www.pedant.cn/2014/07/04/webview-js-java-interface-research/)>核心JS全解析 2. 核心JS解析如下,欢迎拍砖!!! javascript: (function(win) {     console.log("HostApp initialization begin");     //win.HostApp对象     var 

vuex及其五大核心功能运用解析

什么是vuex? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 什么情况下使用vuex? 如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的.确实是如此——如果您的应用够简单,您最好不要使用 Vuex.一个简单的 store 模式就足够您所需了.但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择. vuex流

微信消息体签名及加解密功能详细解析以及.net实现

原文:微信消息体签名及加解密功能详细解析以及.net实现 前言 微信消息体签名及加密功能已上线,明文传输确实存在安全风险,鉴于微信的用户范围使用之广泛,必定会成为众矢之的.所以大家还是尽快接入安全模式为好.仔细阅读官方接入指南,发现这次安全升级只是涉及到用户在微信对话窗口中与公众好消息交互,所以此次升级还是比较简单的.下面为大家一一道来. 一.功能解析 微信消息体签名及加密功能已上线,出于安全考虑,强烈建议您尽快接入消息加密功能,消除安全风险.详见公告.公众平台接口调试工具已经全面支持消息体加密

[转] Android:微信授权登录与微信分享全解析

https://wohugb.gitbooks.io/wechat/content/qrconnent/refresh_token.html http://blog.csdn.net/xiong_it/article/details/48317527 PS: access_token是微信认证成功和微信平台做交互用的,access_token有2小时有效期.如果access_token过期后,使用refresh_token获得新的access_token.refresh_token的有效期为30

Android:微信授权登录与微信分享全解析

前言 在移动互联网浪潮中,联网APP已经把单机拍死在沙滩上,很多公司都希望自家应用能够有一套帐号系统,可是许多用户却并不一定买账:我凭啥注册你家应用的帐号?微博,微信,QQ几乎成了每个人手机中的必装应用,于是微信,微博,QQ说了:来来来,你们都可以用我家的帐号登录你家应用,只要你遵循OAuth2.0协议标准就行.于是第三方社交帐号登陆成为了许多新兴应用的选择,由于腾讯官方微信开放平台的在线文档相对最新的SDK有些出入,并且登录相关的文档结构次序有些紊乱,今天就把我的一些经验记录在此,对微信开放平

Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/53939176 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每天都有文章更新. 在本系列的上一篇文章中,我们学习了Glide的基本用法,体验了这个图片加载框架的强大功能,以及它非常简便的API.还没有看过上一篇文章的朋友,建议先去阅读 Android图片加载框架最全解析(一),Glide的基本用法 . 在多数情况下,我们想要在界面上加载并展示一

Java生鲜电商平台-电商订单系统全解析

Java生鲜电商平台-电商订单系统全解析 今天分享将会分为以下三个环节来阐述: 1.订单系统的介绍 2.订单系统的解构 3.垂直电商订单系统设计思路 一.什么是订单系统? 订单管理系统(OMS)是物流管理系统的一部分,通过对客户下达的订单进行管理及跟踪,动态掌握订单的进展和完成情况,提升物流过程中的作业效率,从而节省运作时间和作业成本,提高物流企业的市场竞争力.顾名思义,电商系统就是用户.平台.商户等对于订单的管控.跟踪的系统,衔接着商品中心.wms.促销系统.物流系统等,是电子商务的基础模块:

OpenCV 2.4.8组件结构全解析

转自: http://blog.csdn.net/huang9012/article/details/21811271 之前啃了不少OpenCV的官方文档,发现如果了解了一些OpenCV整体的模块架构后,再重点学习自己感兴趣的部分的话,就会有一览众山小的感觉,于是,就决定写出这篇文章,作为启程OpenCV系列博文的第二篇. 至于OpenCV组件结构的研究方法,我们不妨管中窥豹,通过opencv安装路径下include目录里面头文件的分类存放,来一窥OpenCV这些年迅猛发展起来的庞杂组件架构.

Storyboard 全解析

XCode 4.3.2 新功能 - Storyboard 最近开始比较有空在玩 XCode 4.3.2,赫然发现它多了个 Storyboard 的东东. Storyboard 这个东西一般来说是在做创意发想的时候,用来将自己的想的一些故事情节画成像是连环漫画一样,想不到 Apple 把它用在这里,真是佩服... 好吧,不废话,先来说说这个 Storyboard 带来什么改变? 在这个版本前,我们在设计画面的时候都是用 interface builder 产生一个 xib 档,然后在 code 要