云通讯
首先我们要去网易云通信上注册一个账号:网址:https://netease.im/
github:代码网址:https://github.com/qianshao1030/Tongxu
代码实现
Activity布局:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:tools="http://schemas.android.com/tools" 4 android:id="@+id/activity_main" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 android:orientation="vertical" 8 tools:context="com.example.asus.tongxun.MainActivity"> 9 <TextView 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:layout_gravity="center_horizontal" 13 android:background="@android:color/holo_green_light" 14 android:gravity="center" 15 android:paddingBottom="10dp" 16 android:paddingTop="10dp" 17 android:text="登录" 18 android:textColor="@android:color/white" 19 android:textSize="20sp" /> 20 21 <LinearLayout 22 android:layout_width="match_parent" 23 android:layout_height="wrap_content" 24 android:layout_marginTop="20dp" 25 android:orientation="horizontal" 26 android:paddingLeft="20dp" 27 android:paddingRight="20dp"> 28 29 <TextView 30 android:layout_width="wrap_content" 31 android:layout_height="wrap_content" 32 android:text="帐号:" 33 android:textColor="@color/colorAccent" /> 34 35 <EditText 36 android:id="@+id/tv_account" 37 android:layout_width="match_parent" 38 android:layout_height="wrap_content" 39 android:hint="请输入您的帐号!" /> 40 </LinearLayout> 41 42 <LinearLayout 43 android:layout_width="match_parent" 44 android:layout_height="wrap_content" 45 android:layout_marginTop="20dp" 46 android:orientation="horizontal" 47 android:paddingLeft="20dp" 48 android:paddingRight="20dp"> 49 50 <TextView 51 android:layout_width="wrap_content" 52 android:layout_height="wrap_content" 53 android:text="密码:" 54 android:textColor="@color/colorAccent" /> 55 56 <EditText 57 android:id="@+id/tv_pw" 58 android:layout_width="match_parent" 59 android:layout_height="wrap_content" 60 android:hint="请输入您的帐号!" /> 61 </LinearLayout> 62 63 <Button 64 android:id="@+id/btn_login" 65 android:layout_width="match_parent" 66 android:layout_height="wrap_content" 67 android:layout_marginTop="60dp" 68 android:text="登录!" /> 69 70 </LinearLayout>
Activity:
1 public class MainActivity extends AppCompatActivity implements View.OnClickListener { 2 3 private EditText tv_account; 4 private EditText tv_pw; 5 private Button btn_login; 6 7 @Override 8 protected void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState); 10 setContentView(R.layout.activity_main); 11 initView(); 12 } 13 14 private void initView() { 15 tv_account = (EditText) findViewById(R.id.tv_account); 16 tv_pw = (EditText) findViewById(R.id.tv_pw); 17 btn_login = (Button) findViewById(R.id.btn_login); 18 19 btn_login.setOnClickListener(this); 20 } 21 22 @Override 23 public void onClick(View v) { 24 switch (v.getId()) { 25 case R.id.btn_login: 26 //封装登录信息. 27 LoginInfo info 28 = new LoginInfo(tv_account.getText().toString(),tv_pw.getText().toString()); 29 //请求服务器的回调 30 RequestCallback<LoginInfo> callback = 31 new RequestCallback<LoginInfo>() { 32 @Override 33 public void onSuccess(LoginInfo param) { 34 DemonstrateUtil 35 .showLogResult("onSuccess--"+param.getAccount()+"--"+param.getToken()); 36 DemonstrateUtil.showToastResult(MainActivity.this,"登录成功!"); 37 38 // 可以在此保存LoginInfo到本地,下次启动APP做自动登录用 39 40 //跳转到消息页面 41 startActivity(new Intent(MainActivity.this,WelcomeActivity.class)); 42 finish(); 43 } 44 45 @Override 46 public void onFailed(int code) { 47 DemonstrateUtil.showLogResult("登录失败!返回码"+code); 48 } 49 50 @Override 51 public void onException(Throwable exception) { 52 DemonstrateUtil.showLogResult(exception.toString()); 53 } 54 55 }; 56 //发送请求. 57 NIMClient.getService(AuthService.class).login(info) 58 .setCallback(callback); 59 break; 60 } 61 } 62 }
Activity聊天布局:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:tools="http://schemas.android.com/tools" 4 android:id="@+id/activity_welcome" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 android:orientation="vertical" 8 tools:context="com.example.asus.tongxun.WelcomeActivity"> 9 <TextView 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:layout_gravity="center_horizontal" 13 android:background="@android:color/holo_green_light" 14 android:gravity="center" 15 android:paddingBottom="10dp" 16 android:paddingTop="10dp" 17 android:text="单聊" 18 android:textColor="@android:color/white" 19 android:textSize="20sp" /> 20 21 <LinearLayout 22 android:layout_width="match_parent" 23 android:layout_height="0dp" 24 android:layout_weight="1" 25 android:orientation="vertical" 26 android:paddingLeft="20dp" 27 android:paddingRight="20dp"> 28 29 <TextView 30 android:layout_width="wrap_content" 31 android:layout_height="wrap_content" 32 android:text="收到的消息:" /> 33 34 <TextView 35 android:id="@+id/tv_recivetv_in" 36 android:layout_width="wrap_content" 37 android:layout_height="0dp" 38 android:layout_weight="1" 39 android:text="1111" 40 android:textColor="@android:color/holo_red_light" /> 41 42 <TextView 43 android:layout_width="wrap_content" 44 android:layout_height="wrap_content" 45 android:text="发出的消息:" /> 46 47 <TextView 48 android:id="@+id/tv_send_out" 49 android:layout_width="wrap_content" 50 android:layout_height="0dp" 51 android:layout_weight="1" 52 android:text="2222" 53 android:textColor="@android:color/holo_blue_light" /> 54 </LinearLayout> 55 56 <EditText 57 android:id="@+id/et_input" 58 android:layout_width="match_parent" 59 android:layout_height="wrap_content" 60 android:layout_marginLeft="20dp" 61 android:layout_marginRight="20dp" 62 android:layout_marginTop="5dp" 63 android:hint="输入消息..." /> 64 65 <LinearLayout 66 android:layout_width="match_parent" 67 android:layout_height="wrap_content" 68 android:orientation="horizontal" 69 android:paddingLeft="10dp" 70 android:paddingRight="10dp"> 71 72 <Button 73 android:id="@+id/btn_select_people" 74 android:layout_width="0dp" 75 android:layout_height="wrap_content" 76 android:layout_weight="1" 77 android:text="选择联系人" /> 78 79 <Button 80 android:id="@+id/btn_send" 81 android:layout_width="0dp" 82 android:layout_height="wrap_content" 83 android:layout_weight="1" 84 android:text="发送" /> 85 86 <Button 87 android:id="@+id/btn_out" 88 android:layout_width="0dp" 89 android:layout_height="wrap_content" 90 android:layout_weight="1" 91 android:text="退出" /> 92 </LinearLayout> 93 94 </LinearLayout>
聊天的Activity:
1 public class WelcomeActivity extends AppCompatActivity implements View.OnClickListener { 2 3 private TextView tv_recivetv_in; 4 private TextView tv_send_out; 5 private EditText et_input; 6 private Button btn_select_people; 7 private Button btn_send; 8 private Button btn_out; 9 10 private Observer<List<IMMessage>> incomingMessageObserver; 11 12 @Override 13 protected void onCreate(Bundle savedInstanceState) { 14 super.onCreate(savedInstanceState); 15 setContentView(R.layout.activity_welcome); 16 initView(); 17 //注册消息观察者,registerObserver 18 registerObserver(); 19 } 20 21 private void registerObserver() { 22 // 处理新收到的消息,为了上传处理方便,SDK 保证参数 messages 全部来自同一个聊天对象。 23 //消息接收观察者 24 incomingMessageObserver = new Observer<List<IMMessage>>() { 25 @Override 26 public void onEvent(List<IMMessage> imMessages) { 27 // 处理新收到的消息,为了上传处理方便,SDK 保证参数 messages 全部来自同一个聊天对象。 28 IMMessage imMessage = imMessages.get(0); 29 tv_recivetv_in.setText(imMessage.getFromNick() + "-->:" + imMessage.getContent()); 30 account = imMessage.getFromAccount(); 31 } 32 }; 33 //注册消息接收观察者, 34 //true,代表注册.false,代表注销 35 NIMClient.getService(MsgServiceObserve.class) 36 .observeReceiveMessage(incomingMessageObserver, true); 37 } 38 39 private void initView() { 40 tv_recivetv_in = (TextView) findViewById(R.id.tv_recivetv_in); 41 tv_send_out = (TextView) findViewById(R.id.tv_send_out); 42 et_input = (EditText) findViewById(R.id.et_input); 43 btn_select_people = (Button) findViewById(R.id.btn_select_people); 44 btn_send = (Button) findViewById(R.id.btn_send); 45 btn_out = (Button) findViewById(R.id.btn_out); 46 47 btn_select_people.setOnClickListener(this); 48 btn_send.setOnClickListener(this); 49 btn_out.setOnClickListener(this); 50 } 51 52 @Override 53 public void onClick(View v) { 54 switch (v.getId()) { 55 case R.id.btn_select_people: 56 //选择联系人. 57 final String[] accounts = {"1690152226", "2871794243","123456"}; 58 final String[] items = { 59 "小鸟", 60 "大鸟", 61 "小梁", 62 }; 63 DialogUtil.showListDialog(WelcomeActivity.this, "请选择联系人!", items, new DialogInterface.OnClickListener() { 64 @Override 65 public void onClick(DialogInterface dialog, int which) { 66 account = accounts[which]; 67 DemonstrateUtil.showToastResult(WelcomeActivity.this, items[which]); 68 } 69 }); 70 break; 71 case R.id.btn_send: 72 //发送消息 73 sendMessage(); 74 break; 75 case R.id.btn_out: 76 //退出登录 77 loginOut(); 78 break; 79 } 80 } 81 private String account = "zxn002"; 82 83 private void sendMessage() { 84 // 以单聊类型为例 85 SessionTypeEnum sessionType = SessionTypeEnum.P2P; 86 String text = et_input.getText().toString(); 87 // 创建一个文本消息 88 IMMessage textMessage = MessageBuilder.createTextMessage(account, sessionType, text); 89 90 // 发送给对方 91 NIMClient.getService(MsgService.class).sendMessage(textMessage, false); 92 tv_send_out.setText(text); 93 } 94 95 private void loginOut() { 96 NIMClient.getService(AuthService.class).logout(); 97 finish(); 98 startActivity(new Intent(this, MainActivity.class)); 99 } 100 101 @Override 102 protected void onDestroy() { 103 super.onDestroy(); 104 //注销消息接收观察者. 105 NIMClient.getService(MsgServiceObserve.class) 106 .observeReceiveMessage(incomingMessageObserver, false); 107 } 108 }
Application:
1 public class NimApplication extends Application{ 2 public void onCreate() { 3 // ... your codes 4 5 // SDK初始化(启动后台服务,若已经存在用户登录信息, SDK 将完成自动登录) 6 NIMClient.init(this, loginInfo(), options()); 7 8 // ... your codes 9 if (NIMUtil.isMainProcess(this)) { 10 // 注意:以下操作必须在主进程中进行 11 // 1、UI相关初始化操作 12 // 2、相关Service调用 13 } 14 } 15 16 // 如果返回值为 null,则全部使用默认参数。 17 private SDKOptions options() { 18 SDKOptions options = new SDKOptions(); 19 20 // 如果将新消息通知提醒托管给 SDK 完成,需要添加以下配置。否则无需设置。 21 StatusBarNotificationConfig config = new StatusBarNotificationConfig(); 22 config.notificationEntrance = WelcomeActivity.class; // 点击通知栏跳转到该Activity 23 config.notificationSmallIconId = R.mipmap.ic_launcher; 24 // 呼吸灯配置 25 config.ledARGB = Color.GREEN; 26 config.ledOnMs = 1000; 27 config.ledOffMs = 1500; 28 // 通知铃声的uri字符串 29 config.notificationSound = "android.resource://com.netease.nim.demo/raw/msg"; 30 options.statusBarNotificationConfig = config; 31 32 // 配置保存图片,文件,log 等数据的目录 33 // 如果 options 中没有设置这个值,SDK 会使用采用默认路径作为 SDK 的数据目录。 34 // 该目录目前包含 log, file, image, audio, video, thumb 这6个目录。 35 String sdkPath = Environment.getExternalStorageDirectory() + "/" + getPackageName() + "/nim"; // 可以不设置,那么将采用默认路径 36 // 如果第三方 APP 需要缓存清理功能, 清理这个目录下面个子目录的内容即可。 37 options.sdkStorageRootPath = sdkPath; 38 39 // 配置是否需要预下载附件缩略图,默认为 true 40 options.preloadAttach = true; 41 42 // 配置附件缩略图的尺寸大小。表示向服务器请求缩略图文件的大小 43 // 该值一般应根据屏幕尺寸来确定, 默认值为 Screen.width / 2 44 options.thumbnailSize = 480/2; 45 46 // 用户资料提供者, 目前主要用于提供用户资料,用于新消息通知栏中显示消息来源的头像和昵称 47 options.userInfoProvider = new UserInfoProvider() { 48 @Override 49 public UserInfo getUserInfo(String account) { 50 return null; 51 } 52 53 @Override 54 public String getDisplayNameForMessageNotifier(String account, String sessionId, 55 SessionTypeEnum sessionType) { 56 return null; 57 } 58 59 @Override 60 public Bitmap getAvatarForMessageNotifier(SessionTypeEnum sessionType, String sessionId) { 61 return null; 62 } 63 }; 64 return options; 65 } 66 67 // 如果已经存在用户登录信息,返回LoginInfo,否则返回null即可 68 private LoginInfo loginInfo() { 69 return null; 70 } 71 }
清单文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.asus.tongxun"> 4 5 <!-- 权限声明 --> 6 <!-- 访问网络状态 --> 7 <uses-permission android:name="android.permission.INTERNET" /> 8 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 9 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> 10 <!-- 控制呼吸灯,振动器等,用于新消息提醒 --> 11 <uses-permission android:name="android.permission.FLASHLIGHT" /> 12 <uses-permission android:name="android.permission.VIBRATE" /> 13 <!-- 外置存储存取权限 --> 14 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 15 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 16 17 <!-- 多媒体相关 --> 18 <uses-permission android:name="android.permission.CAMERA" /> 19 <uses-permission android:name="android.permission.RECORD_AUDIO" /> 20 <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 21 22 <!-- 如果需要实时音视频通话模块,下面的权限也是必须的。否则,可以不加 --> 23 <uses-permission android:name="android.permission.BLUETOOTH" /> 24 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> 25 <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> 26 <uses-permission android:name="android.permission.BROADCAST_STICKY" /> 27 28 <uses-feature android:name="android.hardware.camera" /> 29 <uses-feature android:name="android.hardware.camera.autofocus" /> 30 <uses-feature 31 android:glEsVersion="0x00020000" 32 android:required="true" /> 33 <!-- SDK 权限申明, 第三方 APP 接入时,请将 com.netease.nim.demo 替换为自己的包名 --> 34 <!-- 和下面的 uses-permission 一起加入到你的 AndroidManifest 文件中。 --> 35 <permission 36 android:name="com.example.asus.tongxun.permission.RECEIVE_MSG" 37 android:protectionLevel="signature" /> 38 <!-- 接收 SDK 消息广播权限, 第三方 APP 接入时,请将 com.netease.nim.demo 替换为自己的包名 --> 39 <uses-permission android:name="com.example.asus.tongxun.permission.RECEIVE_MSG" /> 40 41 <application 42 android:name=".NimApplication" 43 android:allowBackup="true" 44 android:icon="@mipmap/ic_launcher" 45 android:label="@string/app_name" 46 android:supportsRtl="true" 47 android:theme="@style/AppTheme"> 48 49 <!-- 50 APP key, 可以在这里设置,也可以在 SDKOptions 中提供。 51 如果 SDKOptions 中提供了,取 SDKOptions 中的值。 52 --> 53 <meta-data 54 android:name="com.netease.nim.appKey" 55 android:value="908e3770fb58ac268e0c5b9c3e341e14" /> 56 57 <!-- 声明网易云通信后台服务,如需保持后台推送,使用独立进程效果会更好。 --> 58 <service 59 android:name="com.netease.nimlib.service.NimService" 60 android:process=":core" /> 61 62 <!-- 运行后台辅助服务 --> 63 <service 64 android:name="com.netease.nimlib.service.NimService$Aux" 65 android:process=":core" /> 66 67 <!-- 声明网易云通信后台辅助服务 --> 68 <service 69 android:name="com.netease.nimlib.job.NIMJobService" 70 android:exported="true" 71 android:permission="android.permission.BIND_JOB_SERVICE" 72 android:process=":core" /> 73 74 <!-- 75 网易云通信SDK的监视系统启动和网络变化的广播接收器,用户开机自启动以及网络变化时候重新登录, 76 保持和 NimService 同一进程 77 --> 78 <receiver 79 android:name="com.netease.nimlib.service.NimReceiver" 80 android:exported="false" 81 android:process=":core"> 82 <intent-filter> 83 <action android:name="android.intent.action.BOOT_COMPLETED" /> 84 <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> 85 </intent-filter> 86 </receiver> 87 88 <!-- 网易云通信进程间通信 Receiver --> 89 <receiver android:name="com.netease.nimlib.service.ResponseReceiver" /> 90 91 <!-- 网易云通信进程间通信service --> 92 <service android:name="com.netease.nimlib.service.ResponseService" /> 93 94 <meta-data 95 android:name="com.netease.cosine.target" 96 android:value="" /> 97 <meta-data 98 android:name="com.netease.cosine.target.receiver" 99 android:value="com.netease.nimlib.service.NimReceiver" /> 100 101 <!-- !!!!!! --> 102 <!-- 103 <provider 104 android:name="com.netease.nimlib.ipc.NIMContentProvider" 105 android:authorities="com.example.asus.tongxun.ipc.provider" 106 android:exported="false" 107 android:process=":core" /> 108 --> 109 110 <activity android:name=".MainActivity"> 111 <intent-filter> 112 <action android:name="android.intent.action.MAIN" /> 113 114 <category android:name="android.intent.category.LAUNCHER" /> 115 </intent-filter> 116 </activity> 117 <activity android:name=".WelcomeActivity"></activity> 118 </application> 119 120 </manifest>
build.gradle:
apply plugin: 'com.android.application' android { compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig { applicationId "com.example.asus.tongxun" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } defaultConfig { ndk { //设置支持的SO库架构 abiFilters "armeabi-v7a", "x86","arm64-v8a","x86_64" } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:26.+' testCompile 'junit:junit:4.12' // 添加依赖。注意,版本号必须一致。 // 基础功能 (必需) compile 'com.netease.nimlib:basesdk:4.4.0' // 音视频和互动白板服务需要 compile 'com.netease.nimlib:nrtc:4.4.0' // 音视频需要 compile 'com.netease.nimlib:avchat:4.4.0' // 聊天室需要 compile 'com.netease.nimlib:chatroom:4.4.0' // 互动白板服务需要 compile 'com.netease.nimlib:rts:4.4.0' // 全文检索服务需要 compile 'com.netease.nimlib:lucene:4.4.0' compile project(':library-demonstrate') }