Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。
效果图:

实现代码:
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/4/19 14:50 * Description : 注册页面 */ class RegisterFragment : BaseDataBindingFragment() { override fun getLayoutRes() = R.layout.wc_register private val userViewModel: UserViewModel by viewModels() private var account: String = "" private var name: String = "" private var password: String = "" private var passwordConfirm: String = "" private var email : String = "" private var navController : NavController? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initViews() } private fun initViews() { super.builder().setTitleContent(R.string.wc_base_top_register) btn_user_register.setOnClickListener { register() } navController = Navigation.findNavController(btn_user_register) userViewModel.insertUserData.observe(viewLifecycleOwner){ TagUtils.d("register 服务器返回:${it} ") //如果同步成功,则重新登录 if(it){ DataStoreUtils.put(DataStoreParams.User.DS_OPENFILE_REGISTER, true) } } } //注册 private fun register() { account = regiter_account.getText().toString().trim() name = regiter_name.getText().toString().trim() password = regiter_password.getText().toString().trim() passwordConfirm = regiter_password_confirm.getText().toString().trim() if(TextUtils.isEmpty(account)){ ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.register_account_empty_tip)) } else if(account.length < 4 || account.length > 18){ ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.register_account_length_tip)) } else if(TextUtils.isEmpty(name)){ ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.register_nickname_empty_tip)) } else if(name.length < 2 || name.length > 16){ ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.register_nickname_length_tip)) } else if(TextUtils.isEmpty(password)){ ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.register_password_empty_tip)) } else if(password.length < 4 || password.length > 18){ ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.register_password_length_tip)) } else if(TextUtils.isEmpty(passwordConfirm)){ ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.register_password_confirm_empty_tip)) } else if(!password.equals(passwordConfirm)){ ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.register_password_different_tip)) } else { email = account +"@163.com"//默认设置email信息 DataStoreUtils.put(DataStoreParams.User.DS_OPENFILE_REGISTER, false) showLoadingDialog() CoroutineScope(Dispatchers.IO).launch { try { TagUtils.d("register 开始注册") val reg = Registration() //设置类型 reg.type = IQ.Type.SET //发送到服务器 reg.to = WcApp.getXmppConnection().serviceName //设置用户名 reg.setUsername(account) //设置密码 reg.setPassword(password) //设置其余属性 不填可能会报500异常 连接不到服务器 amack一个Bug reg.addAttribute("name", name) reg.addAttribute("email", email) reg.addAttribute("android", "geolo_createUser_android") //设置安卓端登录 var connection = WcApp.getXmppConnection() TagUtils.d("register 开始注册 connect ") connection.connect() //创建包过滤器 val filter: PacketFilter = AndFilter(PacketIDFilter(reg.packetID), PacketTypeFilter(IQ::class.java)) //创建包收集器 val collector = connection.createPacketCollector(filter) //发送包 connection.sendPacket(reg) //获取返回信息 val result = collector.nextResult(SmackConfiguration.getPacketReplyTimeout().toLong()) as IQ // 停止请求results(是否成功的结果) collector?.cancel() TagUtils.d("register 开始注册 connect2 ${Gson().toJson(result)}") //通过返回信息判断 if (result == null) { registerResultTip(BaseUtils.getString(R.string.wc_register_xmpp_no_response)) } else if (result.type === IQ.Type.ERROR) { if (result.error.toString() .equals("conflict(409)", ignoreCase = true) ) { //账户已经存在, registerResultTip(BaseUtils.getString(R.string.wc_register_account_exist, account)) CoroutineScope(Dispatchers.Main).launch { //注册成功跳转登录页面,重新登录。有可能没同步到web服务器 Navigation.findNavController(btn_user_register).popBackStack() } } else { TagUtils.d("register 注册失败 connect2 ${Gson().toJson(result.error)}") registerResultTip(BaseUtils.getString(R.string.wc_register_failure)) } } else if (result.type === IQ.Type.RESULT) { TagUtils.d("register 开始注册 connect account = ${account}, ${password}") connection.login(account, password) val presence = Presence(Presence.Type.available ) connection.sendPacket(presence) var userBean = UserBean(account = account, name = name, nickName = name, address = "", email = "", phone = "", avatar = "", birthday = "", note = "") DataStoreUtils.put(DataStoreParams.User.DS_ACCOUNT, account) DataStoreUtils.put(DataStoreParams.User.DS_PASSWORD, password) DataStoreUtils.put(DataStoreParams.User.DS_NICKNAME, name) DataStoreUtils.put(DataStoreParams.User.DS_TEMP_USER_BEAN, Gson().toJson(userBean)) //WcApp.setUserBean(userBean) //插入本地数据库 userViewModel.insertUserLocal(userBean) //上传到服务器 userViewModel.insertUser(userBean) registerResultTip(BaseUtils.getString(R.string.wc_register_success)) TagUtils.d("register 开始注册 成功 ") CoroutineScope(Dispatchers.Main).launch { //注册成功跳转登录页面,重新登录。有可能没同步到web服务器 navController?.previousBackStackEntry?.savedStateHandle?.set(CommonUtils.User.IS_REGISTER_BACK, true) navController?.popBackStack() } } else { registerResultTip(BaseUtils.getString(R.string.wc_register_failure)) } } catch (e: Exception) { TagUtils.d("register 开始注册 异常:${e.message} ") e.printStackTrace() registerResultTip(BaseUtils.getString(R.string.wc_register_failure)) } } } } /** * 注册失败提示 */ private fun registerResultTip(msg : String){ TagUtils.d("register 开始注册 对话框消失 ") CoroutineScope(Dispatchers.Main).launch { ToastUtils.makeText(requireActivity(), msg) dismissLoadingDialog() } } private var loadingUtils : BaseDialogUtils? = null //显示加载对话框 private fun showLoadingDialog(){ loadingUtils = BaseDialogUtils(requireActivity()) loadingUtils!!.builder() .hideCancel() .hideConfirm() .setCancelable(true) .setOnLoadingClick(object : BaseDialogUtils.OnLoadingClick{ override fun onClickCancel() { ToastUtils.makeText(requireActivity(), "对话框取消按钮") } override fun onClickConfirm() { ToastUtils.makeText(requireActivity(), "对话框确定按钮") } }) loadingUtils?.show() } //隐藏加载对话框 private fun dismissLoadingDialog(){ loadingUtils?.dismiss() } }