前言
- 这是我发布的第一篇文章,我在此之前写过十几篇关于技术的文章。后来觉得写的太烂了,我我我删了....(后悔了)
- 本篇文章教会如何整合Spring Boot + Netty + Websocket(别想太多,简单通讯还好,如果要开发IM系统。还有庞大的逻辑等你处理....)
最近开始弄ios app,发现个好用的工具App Uploader AppUploader是一款用于发布iOS应用程序的自动化工具,它可以帮助开发者快速、简便地打包并上传应用程序至App Store。本文将为您介绍AppUploader的基本功能以及如何使用它来发布您的iOS应用程序。
一、AppUploader的基本功能
- 打包和上传应用程序:AppUploader可以自动打包并上传应用程序至App Store,省去了手动操作的繁琐过程;
- 自动生成证书:AppUploader可以自动生成开发和发布所需的证书,大大简化了证书管理的流程;
- 快速、简便的登录:AppUploader支持快速登录Apple开发者账号,同时也支持多账号管理;
- 支持多种语言:AppUploader支持多种语言,包括简体中文、繁体中文、英语等,可以轻松适配不同用户的需求;
AppUploader使用教程 一、安装 AppUploader 注意您账号需要支付688给apple,不然只能创建开发证书,无法提交上传发布,无法使用apple登录,支付,推送等功能
- 下载 AppUploader:您可以在 AppUploader 的官网上下载相应的软件版本(www.applicationloader.net/)。
- 安装 AppUploader:双击下载后的安装包,按照安装程序的提示完成安装即可。
- 登录 Apple 开发者账号:打开 AppUploader 软件,选择登录,输入您的 Apple 开发者账号和密码,然后点击登录按钮即可完成登录。
二、上传应用程序
- 打包应用程序:在 Xcode 中打开您的应用程序项目,并进行 Archive 操作来生成 .ipa 文件。
- 上传应用程序:回到 AppUploader 软件,选择“提交测试”,在右上方点击“选择IPA”栏中选择您的 .ipa 文件路径,然后填写其他必要信息(如 Bundle ID、应用程序名称等),最后点击“Upload”按钮即可开始上传应用程序。
- 查看上传进度:上传过程中,您可以查看上传进度和详细日志信息,以便及时发现和解决问题。
各大技术介绍
Spring boot
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
Netty
Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基于NIO的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。 “快速”和“简单”并不用产生维护性或性能上的问题。Netty 是一个吸收了多种协议(包括FTP、SMTP、HTTP等各种二进制文本协议)的实现经验,并经过相当精心设计的项目。最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。
WebSocket
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
(以上从百度上搜索)
开始整合代码
- 创建一个Spring Boot项目
- 配置(复制粘贴)application.properties;(注:8011是端口,如果你系统上占用的话,就可以换个端口 比如:8012 8013等等)
# 配置启动端口
server.port = 8011
- 启动项目(如果项目启动正常,请前往下一步。如果启动项目失败。请检查)
- 将依赖加入pom.xml
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.25.Final</version>
</dependency>
5.初始化通道加载器
新建文件 WebSocketChannelInitializer.java
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
/**
* @author 二货
* 初始化通道
*
* <pre>
* 继承ChannelInitializer<SocketChannel> 实现initChannel方法
* </pre>
*/
public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel>{
/**
* 配置对应的ChannelHandler
* @param socketChannel
* @throws Exception
*/
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获取对应的管道
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline
//添加HTTP编码解码器
.addLast(new HttpServerCodec())
//添加对大数据流的支持
.addLast(new ChunkedWriteHandler())
//添加聚合器
.addLast(new HttpObjectAggregator(1024 * 64))
//设置websocket连接前缀前缀
.addLast(new WebSocketServerProtocolHandler("/ws"))
//添加自定义处理器(这个ChatHandler请继续看文章)
.addLast(new ChatHandler());
}
}
- 自定义处理器
新建ChatHandler.java 这里处理建立连接,关闭连接,接收消息,异常等
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
/**
* 自定义处理器
* @author 二货
* <pre>
* 继承SimpleChannelInboundHandler<TextWebSocketFrame>并实现channelRead0(通道读取)
* </pre>
*/
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
/**
* 创建ChannelGroup对象存储所有连接的用户
*/
private static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 有新消息时会调用这个方法
*
* @param channelHandlerContext 上下文处理器
* @param textWebSocketFrame 文本
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
//获取客户端发送的消息内容
String text = textWebSocketFrame.text();
System.out.println("收到客户端发送来的消息: " + text);
//遍历出所有连接的通道
for (Channel channel : clients) {
//推送给所有的通道
channel.writeAndFlush(new TextWebSocketFrame("服务器: 收到客户端发送来的消息: " + text));
}
}
/**
* 有新的连接建立时
*
* @param ctx
* @throws Exception
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//加入通道组
clients.add(ctx.channel());
}
/**
* 不活跃时会调用这个方法
*
* @param ctx
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
//移除出通道组
clients.remove(ctx.channel());
}
}
- 配置启动器
新建WebSocketNettyServer.java
import eti.wjc.service.WebSocketNettyServer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author 二货
*/
@Component
public class WebSocketNettyServer {
/**
* Netty服务器启动对象
*/
private final ServerBootstrap serverBootstrap;
public WebSocketNettyServer() {
serverBootstrap = new ServerBootstrap();
// 初始化服务器启动对象
// 主线程池
NioEventLoopGroup mainGrp = new NioEventLoopGroup();
// 从线程池
NioEventLoopGroup subGrp = new NioEventLoopGroup();
serverBootstrap
// 指定使用上面创建的两个线程池
.group(mainGrp, subGrp)
// 指定Netty通道类型
.channel(NioServerSocketChannel.class)
// 指定通道初始化器用来加载当Channel收到事件消息后
.childHandler(new WebSocketChannelInitializer());
}
public void start() {
// 绑定服务器端口,以异步的方式启动服务器
ChannelFuture future = serverBootstrap.bind(12424);
}
}
- 添加启动监听器
新建NettyStartListener.java
import eti.wjc.service.WebSocketNettyServer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author二货
* <pre>
* 实现ApplicationListener<ContextRefreshedEvent>的onApplicationEvent方法
* </pre>
*/
@Component
public class NettyStartListener implements ApplicationListener<ContextRefreshedEvent> {
/**
* 注入启动器
*/
@Resource
private WebSocketNettyServer webSocketNettyServer;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
//判断event上下文中的父级是否为空
if (event.getApplicationContext().getParent() == null) {
try {
//为空则调用start方法
webSocketNettyServer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
启动项目 使用 WebSocket在线测试 www.websocket-test.com/ 连接地址:ws://127.0.0.1:12424/ws (注意:12424是WebSocketNettyServer.java中start()方法下serverBootstrap.bind(12424)绑定的端口号,而不是项目启动端口号)