即时聊天的解决方案
- socket:
- xmpp:xmpp+openfire+asmack
- 环信
常见协议
比较安全,tcp上还加了俩层
简单聊一下socket
socket:套接字,连接需要ip
和端口
,分为tcp和udp两种形式
常见的术语
- xmpp:基于xml的可拓展协议.
- jabber:xmpp的前身.
- openfire:支持xmpp的开源服务器
- smack.jar:对xmpp协议封装.方便开发的jar包.
- spark.exe:基于xmpp的pc客户端;
- asmack.jar:smack.jar的精简版.专门针对android端开发
xmpp的认识.
- xmpp官网:http://xmpp.org/
-
XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测。XMPP的前身是Jabber,一个开源形式组织产生的网络即时通信协议。
xmpp特点:
- 开放: XMPP协议是自由、开放、公开的,并且易于了解。 而且在客户端 、 服务器 、 组件 、 源码库等方面,都已经各自有多种实现。
- 标准: 互联网工程工作小组( IETF )已经将Jabber的核心XML流协议以XMPP之名,正式列为认可的实时通信及Presence技术。 而XMPP的技术规格已被定义在RFC3920及RFC3921 。 任何IM供应商在遵循XMPP协议下,都可与Google Talk实现连接。
- 证实可用: 第一个Jabber(现在XMPP)技术是Jeremie Miller在1998年开发的,现在已经相当稳定;数以百计的开发者为XMPP技术而努力。 今日的互联网上有数以万计的XMPP服务器运作着,并有数以百万计的人们使用XMPP实时传讯软件。
- 分散式: XMPP网络的架构和电子邮件十分相像;XMPP核心协议通信方式是先创建一个stream,XMPP以TCP传递XML数据流,没有中央主服务器。 任何人都可以运行自己的XMPP服务器,使个人及组织能够掌控他们的实时传讯体验。
- 安全: 任何XMPP协议的服务器可以独立于公众XMPP网络(例如在企业内部网络中),而使用SASL及TLS等技术的可靠安全性,已自带于核心XMPP技术规格中。
- 可扩展: XML 命名空间的威力可使任何人在核心协议的基础上建造定制化的功能;为了维持通透性,常见的扩展由XMPP标准基金会 。 弹性佳 XMPP除了可用在实时通信的应用程序,还能用在网络管理、内容供稿、协同工具、文件共享、游戏、远程系统监控等。
- 多样性: 用XMPP协议来建造及布署实时应用程序及服务的公司及开放源代码计划分布在各种领域;用XMPP技术开发软件,资源及支持的来源是多样的,使得使你不会陷于被“绑架”的困境。
相关的下载
asmack github:https://github.com/Flowdalic/asmack
asmack下载地址1:http://asmack.freakempire.de/
asmack下载地址2:http://code.google.com/p/asmack/downloads/list
openfire下载地址:http://www.igniterealtime.org/downloads/index.jsp
smack使用指南:http://www.igniterealtime.org/builds/smack/docs/latest/documentation/index.html
openfire的安装
- 官网
http://www.igniterealtime.org/
- 安装包的类型
- exe安装包-->点击exe根据提示安装
- zip包解压版-->解压放到指定目录就可以了.
- 首次运行的配置
- 配置语言-->
中文简体
- 配置数据库形式-->
内嵌数据库
- 配置服务器名称-->
itheima
- 配置管理员账号密码-->
admin admin。帐号就是这个,没有@xxx那些
- 配置语言-->
- 创建用户
- admin admin
- hm1 111111
spark的安装-->xmpp客户端1
- 直接下一步就可以完成
- 运行
- 1.配置服务器ip
- 2.输入用户账号/密码
如意通的安装-->xmpp客户端2
pc端-服务器-pc端演示
smack常见api的查看.
xmpp版即使聊天的核心:其实就是熟悉asmack.jar里面的一些常见类.以及常见监听器;
工程搭建
- asmack.jar的下载,下载地址
http://asmack.freakempire.de/
- 创建android工程.
- 添加jar包.添加依赖
- as关联源码.
引导页模块splashActivity
ThreadUtils的封装.
public class ThreadUtils { /** * 子线程执行task */ public static void runInThread(Runnable task) { new Thread(task).start(); } /** * 创建一个主线程中handler */ public static Handler mHandler = new Handler(); /** * UI线程执行task */ public static void runInUIThread(Runnable task) { mHandler.post(task); } } public class { /** * 可以在子线程中弹出toast * * @param context * @param text */ public static void showToastSafe(final Context context, final String text) { ThreadUtils.runInUIThread(new Runnable() { @Override public void run() { Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); } }); } }
SplashActivity
public class SplashActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); // 停留3s,进入登录界面 ThreadUtils.runInThread(new Runnable() { @Override public void run() { // 休眠3s SystemClock.sleep(3000); // 进入主界面 Intent intent = new Intent(SplashActivity.this, LoginActivity.class); startActivity(intent); finish(); } }); } }
登录模块LoginActivity
- 引入了
ButterKnife.jar
以及as的android-butterknife-zelezny
插件 - ButterKnife:类似xutils中的viewUtils,可以注解的框架,图为关联源码,点右面
- 调用api登录
连接配置
// 设置常见的参数 config.setDebuggerEnabled(true);// 开启调试模式,可以看到传输的xml config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);//明文传输
public class LoginActivity extends ActionBarActivity { public static final String HOST = "192.168.1.100"; // 主机ip public static final int PORT = 5222; // 对应的端口号 public static final String SERVICENAME = "itheima.com"; private TextView mEtUserName; private TextView mEtPassWord; private Button mBtnLogin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initView(); initListener(); } private void initListener() { mBtnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String userName = mEtUserName.getText().toString(); final String passWord = mEtPassWord.getText().toString(); // 判断用户名是否为空 if (TextUtils.isEmpty(userName)) {// 用户名为空,系统自带的textview的属性,弹出悬浮窗提示 mEtUserName.setError("用户名不能为空"); return; } // 判断密码是否为空 if (TextUtils.isEmpty(passWord)) {// 用户名为空 mEtPassWord.setError("密码不能为空"); return; } ThreadUtils.runInThread(new Runnable() { @Override public void run() { try { // 1.创建连接配置对象 ConnectionConfiguration config = new ConnectionConfiguration(HOST, PORT); // 额外的配置(方面我们开发,上线的时候,可以改回来) config.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);// 明文传输 config.setDebuggerEnabled(true);// 开启调试模式,方便我们查看具体发送的内容 // 2.开始创建连接对象 XMPPConnection conn = new XMPPConnection(config); // 开始连接 conn.connect(); // 连接成功了 // 3.开始登录 conn.login(userName, passWord); // 已经成功成功 ToastUtils.showToastSafe(LoginActivity.this, "登录成功"); finish(); // 跳到主界面 Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); // 需要保存连接对象 IMService.conn = conn; //启动IMService Intent service = new Intent(LoginActivity.this, IMService.class); startService(service); } catch (XMPPException e) { e.printStackTrace(); ToastUtils.showToastSafe(LoginActivity.this, "登录失败"); } } }); } }); } private void initView() { mEtUserName = (TextView) findViewById(R.id.et_username); mEtPassWord = (TextView) findViewById(R.id.et_password); mBtnLogin = (Button) findViewById(R.id.btn_login); } }
主页面MainActivity
ToolBarUtil
public class ToolBarUtil { private List<TextView> mTextViews = new ArrayList<TextView>(); public void createToolBar(LinearLayout container, String[] toolBarTitleArr, int[] iconArr) { for (int i = 0; i < toolBarTitleArr.length; i++) { TextView tv = (TextView) View.inflate(container.getContext(), R.layout.inflate_toolbar_btn, null); tv.setText(toolBarTitleArr[i]); // 动态修改textView里面的drawableTop属性 tv.setCompoundDrawablesWithIntrinsicBounds(0, iconArr[i], 0, 0); int width = 0; int height = LinearLayout.LayoutParams.MATCH_PARENT; LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, height); //设置weight属性 params.weight = 1; container.addView(tv, params); //保存textView到集合中 mTextViews.add(tv); //设置点击事件 final int finalI = i; tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //不同模块之间传值需要用接口回调 //3.需要传值的地方.用接口对象调用接口方法 mOnToolBarClickListener.onToolBarClick(finalI); } }); } } public void changeColor(int position) { //还原所有的颜色 for (TextView tv : mTextViews) { tv.setSelected(false); } mTextViews.get(position).setSelected(true);//通过设置selected属性,控制为选中效果 } //1.创建接口和接口方法 public interface OnToolBarClickListener{ void onToolBarClick(int position); } //2.定义接口变量 OnToolBarClickListener mOnToolBarClickListener; //4.暴露一个公共的方法 public void setOnToolBarClickListener(OnToolBarClickListener onToolBarClickListener) { mOnToolBarClickListener = onToolBarClickListener; } }
MainActivity
public class MainActivity extends ActionBarActivity { @InjectView(R.id.main_tv_title) TextView mMainTvTitle; @InjectView(R.id.main_viewpager) ViewPager mMainViewpager; @InjectView(R.id.main_bottom) LinearLayout mMainBottom; // xutils viewutils 注解方式去找控件 // viewutils httpUitls dbutils bitmaputils // private List<Fragment> mFragments = new ArrayList<Fragment>(); private ToolBarUtil mToolBarUtil; private String[] mToolBarTitleArr; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.inject(this); initData(); initListener(); } private void initListener() { mMainViewpager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { // 修改颜色 mToolBarUtil.changeColor(position); // 修改title mMainTvTitle.setText(mToolBarTitleArr[position]); } @Override public void onPageScrollStateChanged(int state) { } }); mToolBarUtil.setOnToolBarClickListener(new ToolBarUtil.OnToolBarClickListener() { @Override public void onToolBarClick(int position) { mMainViewpager.setCurrentItem(position); } }); } private void initData() { // viewPager-->view-->pagerAdapter // viewPager-->fragment-->fragmentPagerAdapter-->fragment数量比较少 // viewPager-->fragment-->fragmentStatePagerAdapter // 添加fragment到集合中 mFragments.add(new SessionFragment()); mFragments.add(new ContactsFragment()); mMainViewpager.setAdapter(new MyPagerAdapter(getSupportFragmentManager())); // 底部按钮 mToolBarUtil = new ToolBarUtil(); // 文字内容 mToolBarTitleArr = new String[] { "会话", "联系人" }; // 图标内容 int[] iconArr = { R.drawable.selector_meassage, R.drawable.selector_selfinfo }; mToolBarUtil.createToolBar(mMainBottom, mToolBarTitleArr, iconArr); // 设置默认选中会话 mToolBarUtil.changeColor(0); } class MyPagerAdapter extends FragmentPagerAdapter { public MyPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount() { return 2; } } }