jarjava
依賴android
compile 'com.android.support:appcompat-v7:26.1.0' compile 'com.android.support:cardview-v7:26.1.0' compile 'com.android.support:recyclerview-v7:26.1.0'
Android Studio能夠直接添加依賴git
將如下代碼放到項目根目錄的build.gradle文件裏github
repositories { maven { url "https://raw.githubusercontent.com/HyphenateInc/Hyphenate-SDK-Android/master/repository" } }apache
在你的module的build.gradle里加入如下代碼微信
android { //use legacy for android 6.0 useLibrary 'org.apache.http.legacy' } dependencies { compile 'com.android.support:appcompat-v7:23.4.0' //Optional compile for GCM (Google Cloud Messaging). compile 'com.google.android.gms:play-services-gcm:9.4.0' compile 'com.hyphenate:hyphenate-sdk:3.2.3' }app
若是想使用不包含音視頻通話的sdk,用compile 'com.hyphenate:hyphenate-sdk-lite:3.2.3'
maven
權限ide
<!-- 環信 --> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
application標籤內佈局
android:name=".MyApplication"
<!-- 設置環信應用的AppKey --> <meta-data android:name="EASEMOB_APPKEY" android:value="1101170121178296#qqchat"/> <!-- 聲明SDK所需的service SDK核心功能 --> <service android:name="com.hyphenate.chat.EMChatService" android:exported="true" /> <service android:name="com.hyphenate.chat.EMJobService" android:exported="true" android:permission="android.permission.BIND_JOB_SERVICE" /> <!-- 聲明SDK所需的receiver --> <receiver android:name="com.hyphenate.chat.EMMonitorReceiver"> <intent-filter> <action android:name="android.intent.action.PACKAGE_REMOVED" /> <data android:scheme="package" /> </intent-filter> <!-- 可選filter --> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.USER_PRESENT" /> </intent-filter> </receiver>
APP打包混淆
-keep class com.hyphenate.** {*;} -dontwarn com.hyphenate.**
public class MSG { public static final int TYPE_RECEIVED = 0;//消息的類型:接收 public static final int TYPE_SEND = 1; //消息的類型:發送 private String content; private int type; public MSG(String content, int type) { this.content = content; this.type = type; } public String getContent() { return content; } public int getType() { return type; } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:cardview="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/ll_msg_left" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:orientation="horizontal" android:padding="2dp"> <android.support.v7.widget.CardView android:layout_width="wrap_content" android:layout_height="wrap_content" app:cardCornerRadius="20dp" app:cardPreventCornerOverlap="false" app:cardUseCompatPadding="true"> <ImageView android:layout_width="50dp" android:layout_height="50dp" android:scaleType="centerCrop" /> </android.support.v7.widget.CardView> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/chating_left_01_on" android:orientation="horizontal"> <TextView android:id="@+id/tv_msg_left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="10dp" android:textColor="#fff" /> </LinearLayout> </LinearLayout> <LinearLayout android:id="@+id/ll_msg_right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:background="?android:attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:orientation="horizontal" android:padding="2dp"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/chating_right_02" android:orientation="horizontal"> <TextView android:id="@+id/tv_msg_right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="10dp" /> </LinearLayout> <android.support.v7.widget.CardView android:layout_width="wrap_content" android:layout_height="wrap_content" app:cardCornerRadius="20dp" app:cardPreventCornerOverlap="false" app:cardUseCompatPadding="true"> <ImageView android:layout_width="50dp" android:layout_height="50dp" android:scaleType="centerCrop" /> </android.support.v7.widget.CardView> </LinearLayout> </RelativeLayout>
public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.MyViewHolder> { private List<MSG> mMsgList; public MsgAdapter(List<MSG> mMsgList) { this.mMsgList = mMsgList; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = View.inflate(parent.getContext(), R.layout.item_msg, null); MyViewHolder holder = new MyViewHolder(view); return holder; } @Override public void onBindViewHolder(MyViewHolder holder, int position) { MSG msg = mMsgList.get(position); if (msg.getType() == MSG.TYPE_RECEIVED){ holder.llLeft.setVisibility(View.VISIBLE); holder.llRight.setVisibility(View.GONE); holder.tv_Left.setText(msg.getContent()); } else if (msg.getType() == MSG.TYPE_SEND){ holder.llLeft.setVisibility(View.GONE); holder.llRight.setVisibility(View.VISIBLE); holder.tv_Right.setText(msg.getContent()); } } @Override public int getItemCount() { return mMsgList.size(); } static class MyViewHolder extends RecyclerView.ViewHolder{ LinearLayout llLeft; LinearLayout llRight; TextView tv_Left; TextView tv_Right; public MyViewHolder(View itemView) { super(itemView); llLeft = (LinearLayout) itemView.findViewById(R.id.ll_msg_left); llRight = (LinearLayout) itemView.findViewById(R.id.ll_msg_right); tv_Left = (TextView) itemView.findViewById(R.id.tv_msg_left); tv_Right = (TextView) itemView.findViewById(R.id.tv_msg_right); } } }
public class MyApplication extends Application { private Context appContext; @Override public void onCreate() { super.onCreate(); EMOptions options = new EMOptions(); options.setAcceptInvitationAlways(false); appContext = this; int pid = android.os.Process.myPid(); String processAppName = getAppName(pid); // 若是APP啓用了遠程的service,此application:onCreate會被調用2次 // 爲了防止環信SDK被初始化2次,加此判斷會保證SDK被初始化1次 // 默認的APP會在以包名爲默認的process name下運行,若是查到的process name不是APP的process name就當即返回 if (processAppName == null || !processAppName.equalsIgnoreCase(appContext.getPackageName())) { Log.e("--->", "enter the service process!"); // 則此application::onCreate 是被service 調用的,直接返回 return; } //初始化 EMClient.getInstance().init(getApplicationContext(), options); //在作打包混淆時,關閉debug模式,避免消耗沒必要要的資源 EMClient.getInstance().setDebugMode(true); } private String getAppName(int pID) { String processName = null; ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE); List l = am.getRunningAppProcesses(); Iterator i = l.iterator(); PackageManager pm = this.getPackageManager(); while (i.hasNext()) { ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next()); try { if (info.pid == pID) { processName = info.processName; return processName; } } catch (Exception e) { // Log.d("Process", "Error>> :"+ e.toString()); } } return processName; } }
第一個註冊頁面
package xiaweizi.com.qqchat; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.hyphenate.EMCallBack; import com.hyphenate.chat.EMClient; import com.hyphenate.exceptions.HyphenateException; public class RegistActivity extends AppCompatActivity { private static final String TAG = "--->"; private EditText etName; private EditText etPassword; private Button btRegister; private Button btLogin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_regist); etName = (EditText) findViewById(R.id.et_register_name); etPassword = (EditText) findViewById(R.id.et_register_password); btLogin = (Button) findViewById(R.id.bt_login); btRegister = (Button) findViewById(R.id.bt_register); btRegister.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { try { String name = etName.getText().toString().trim(); String password = etPassword.getText().toString().trim(); if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password)){ return; } EMClient.getInstance().createAccount(name, password); toast("註冊成功"); } catch (HyphenateException e) { e.printStackTrace(); Log.i(TAG, "run: " + e); toast("註冊失敗" + e.getDescription()); } } }).start(); } }); btLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String name = etName.getText().toString().trim(); String password = etPassword.getText().toString().trim(); if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password)){ return; } EMClient.getInstance().login(name,password,new EMCallBack() {//回調 @Override public void onSuccess() { EMClient.getInstance().groupManager().loadAllGroups(); EMClient.getInstance().chatManager().loadAllConversations(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(RegistActivity.this, "登錄成功!", Toast.LENGTH_SHORT).show(); //進入聊天界面 startActivity(new Intent(RegistActivity.this, StartActivity.class)); finish(); } }); } @Override public void onProgress(int progress, String status) { } @Override public void onError(int code, String message) { startActivity(new Intent(RegistActivity.this, StartActivity.class)); toast("登錄失敗" + message); } }); } }); } private void toast(final String msg){ runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(RegistActivity.this, msg, Toast.LENGTH_SHORT).show(); } }); } }
第二個匹配頁面
package xiaweizi.com.qqchat; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; public class StartActivity extends AppCompatActivity { private EditText etChatFriend; private Button btStartChat; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_start); etChatFriend = (EditText) findViewById(R.id.et_chat_friend); btStartChat = (Button) findViewById(R.id.bt_start_chat); btStartChat.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String friend = etChatFriend.getText().toString().trim(); if (TextUtils.isEmpty(friend)) return; Intent intent = new Intent(StartActivity.this, ChatActivity.class); intent.putExtra("friend", friend); startActivity(intent); finish(); } }); } }
第三個聊天頁面
package xiaweizi.com.qqchat; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.WindowManager; import android.widget.Button; import android.widget.EditText; import com.hyphenate.EMMessageListener; import com.hyphenate.chat.EMClient; import com.hyphenate.chat.EMMessage; import java.util.ArrayList; import java.util.List; public class ChatActivity extends AppCompatActivity { private static final String TAG = "ChatActivity--->"; private MsgAdapter mAdapter; private RecyclerView mRecyclerView; private EditText etInput; private Button btSend; private List<MSG> mList; private String friend; private EMMessageListener msgListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); setContentView(R.layout.activity_main); friend = getIntent().getStringExtra("friend"); Log.i(TAG, "onCreate: " + friend); mRecyclerView = (RecyclerView) findViewById(R.id.rv_chat); etInput = (EditText) findViewById(R.id.et_input); btSend = (Button) findViewById(R.id.bt_send); initData(); mAdapter = new MsgAdapter(mList); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.setAdapter(mAdapter); btSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String content = etInput.getText().toString().trim(); if (!TextUtils.isEmpty(content)){ //建立一條文本消息,content爲消息文字內容,toChatUsername爲對方用戶或者羣聊的id,後文皆是如此 EMMessage message = EMMessage.createTxtSendMessage(content, friend); //發送消息 EMClient.getInstance().chatManager().sendMessage(message); Log.i(TAG, "發送成功!"); MSG msg = new MSG(content, MSG.TYPE_SEND); mList.add(msg); mAdapter.notifyItemInserted(mList.size() - 1); mRecyclerView.scrollToPosition(mList.size() - 1); etInput.setText(""); } } }); //收到消息 //收到透傳消息 //消息狀態變更 msgListener = new EMMessageListener() { @Override public void onMessageReceived(List<EMMessage> messages) { //收到消息 String result = messages.get(0).getBody().toString(); String msgReceived = result.substring(5, result.length() - 1); Log.i(TAG, "onMessageReceived: " + msgReceived); final MSG msg = new MSG(msgReceived, MSG.TYPE_RECEIVED); runOnUiThread(new Runnable() { @Override public void run() { mList.add(msg); mAdapter.notifyDataSetChanged(); mRecyclerView.scrollToPosition(mList.size() - 1); } }); } @Override public void onCmdMessageReceived(List<EMMessage> messages) { //收到透傳消息 } @Override public void onMessageRead(List<EMMessage> list) { } @Override public void onMessageDelivered(List<EMMessage> list) { } @Override public void onMessageChanged(EMMessage message, Object change) { //消息狀態變更 } }; EMClient.getInstance().chatManager().addMessageListener(msgListener); } @Override protected void onResume() { super.onResume(); } @Override protected void onDestroy() { super.onDestroy(); EMClient.getInstance().chatManager().removeMessageListener(msgListener); } private void initData() { mList = new ArrayList<>(); mList.add(new MSG("日照香爐生紫煙,你與何人在聊天" , MSG.TYPE_SEND)); mList.add(new MSG("黃河之水天上來,就是普通一女孩" , MSG.TYPE_RECEIVED)); mList.add(new MSG("萬水千山只等閒,微信閒扯這麼甜" , MSG.TYPE_SEND)); mList.add(new MSG("日出江花紅勝火,我倆只是談工做" , MSG.TYPE_RECEIVED)); mList.add(new MSG("曾經滄海難爲水,你倆確定有一腿" , MSG.TYPE_SEND)); mList.add(new MSG("除卻巫山不是雲,誰要騙你不是人" , MSG.TYPE_RECEIVED)); } }