移动网关最佳实践(Android)

移动网关接入

使用新版配置文件接入网关

前置条件

您已经部署了新版控制台,支持了新版配置文件(tmf-android-configurations.json)下载。

接入移动网关

TMF基础库内置了移动网关实例,具体接入流程请参考《接入指南

如何切换生产环境与测试环境

集成TMF往往会遇到多套环境并存的情况,如生产环境、测试环境。TMF初始化支持设置不同的配置文件来做环境切换,具体做法如下:

  1. 从控制台下载不同环境的配置文件,并修改配置文件名,如:tmf-android-configurations-uat.json/tmf-android-configurations-sit.json。

  2. 将不同环境配置文件拷贝至assets目录下。

    多配置文件

  3. 初始化基础库时,根据不同编译变体传入不同的配置文件。

    String configAssetName = isUat() ? "tmf-android-configurations-uat.json" : "tmf-android-configurations-sit.json";
    
    TMFBaseConfig config = new TMFBaseConfig.Builder()  
                .configAssetName(configAssetName)
                .build();  
    
    TMFBase.init(CommonApp.get().getApplication(), config);
    

如何调整内置shark实例参数

请参考调整内置shark实例参数

使用旧版配置文件接入网关

如果您还没有部署新版控制台,只能下载到旧版配置文件.java, 那么请参考如下流程接入移动网关。

使用配置文件中的信息创建SharkConfigInfo

说明说明:sharkConfigInfo请参考SharkConfigInfo

示例代码如下:

public static SharkConfigInfo getSharkConfigInfo() {
       SharkConfigInfo info = new SharkConfigInfo();
       info.keyId = TMFConfigurations.TMF_APP_KEY;
       info.productId = TMFConfigurations.TMF_PID;
       info.customId = TMFConfigurations.TMF_CUSTOM_ID;
       info.pubKey = TMFConfigurations.TMF_GW_SKEY;
       info.tcpHost = TMFConfigurations.TMF_GW_TCP_HOST;
       info.tcpPort = TMFConfigurations.TMF_GW_TCP_PORT;
       info.httpUrl = TMFConfigurations.TMF_GW_HTTP_URL;
       //支持ipv6,不是必须的,如果不支持ipv6注释掉如下代码即可
       info.supportIPv6 = TMFConfigurations.SUPPORT_IPV6;
       info.tcpHostIPv6 = TMFConfigurations.TMF_GW_TCP_HOST;
       info.tcpPortIPv6 = TMFConfigurations.TMF_GW_TCP_PORT;
      info.httpUrlIPv6 = TMFConfigurations.TMF_GW_HTTP_URL;
       return info;
}

创建SharkConfig

使用AbsSharkConfig创建SharkConfig,实现getConfig()方法,返回SharkConfigInfo。示例代码如下:

SharkConfig sharkConfig = new AbsSharkConfig() {
    @Override
    protected SharkConfigInfo getConfig() {
        return getSharkConfigInfo();
    }
};

创建ISharkOutlet

  1. 定义sharkPkg/instanceName

    说明说明:部分业务在一个APP或一个进程内开启两个长连接,分别连到不同的Server地址、分别注册各自的GUID。为了满足此类需求,引入了SharkPkg的概念,通过SharkPkg+instanceName标识一个Shark实例,同一个SharkPkg下多个的Shark实例共享数据,共有一个GUID。

    一般情况下您不会有多实例场景存在,因此SharkPkg记instanceName采用如下实现即可:

     String sharkPkg = context.getPackageName() + "_TMF";
     String instanceName = "TMF";
    
  2. 使用AbsSharkOutlet创建ISharkOutlet,实现onGetVersionName,onGetBuildNo,onGetChannel

    注意注意:buildno是应用更新、热修复等组件判断版本的重要依据,具体规则请参考应用发布

     ISharkOutlet sharkOutlet = new AbsSharkOutlet(sharkPkg, sharkConfig, SharkCommonConst.SERVER_TYPE_RELEASE) {
         @Override
         public String onGetVersionName() {
             return VERSION_NAME; 
         }
    
         @Override
         public int onGetBuildNo() {
             return 1000000;
         }
    
         @Override
         public String onGetChannel() {
             return CHANNEL;
         }
     }
    

创建IServiceFactory

Shark允许您自定义线程池及加密服务,TMF已经实现了默认的线程池及国密加密,您可以直接使用,IServiceFactory默认实现如下:

IServiceFactory serviceFactory = new ServiceFactoryWrapper();
private static class ServiceFactoryWrapper implements IServiceFactory {
    g
    /**
     * 线程池
     */
    @Override
    public ISharkThreadPool getSharkThreadPool() {
        return new SimpleThreadPool();
    }

    /**
     * 安全信道使用的加解密算法
     * 非对称加密使用国密SM2,对称加密使用国密SM4ECB
     */
    @Override
    public ISharkCryptor getSharkCryptor() {
        return new ISharkCryptor() {
            @Override
            public byte[] encrypt ( byte[] data, byte[] key){
                return SmCryptor.sm4EncryptECB(data, key);
            }

            @Override
            public byte[] decrypt ( byte[] data, byte[] key){
                return SmCryptor.sm4DecryptECB(data, key);
            }

            @Override
            public byte[] asymmetricEncrypt ( byte[] data, byte[] publicKey){
                return SmCryptor.sm2Encrypt(data, publicKey);
            }

            @Override
            public byte[] asymmetricDecrypt ( byte[] data, byte[] privateKey){
                return SmCryptor.sm2Decrypt(data, privateKey);
            }
        };
    }
}

创建shark实例

// 创建的Shark实例是否包括TCP长连接通道
// 对于一个Server地址,后台推送的依据是GUID,因此每个GUID最多只能与其建一个长连接,
// 如果APP有多个进程使用Shark,则最多只有其中一个进程的Shark实例开启长连接,
// 一般来说一个就已经足够了。如果非要建立多个长连接,则必须使用不同的sharkPkg区分以免数据冲突。
boolean withTcpChannel = true;
// 是否自动开启长连接
// 只有withTcpChannel为true时才有意义。如果不自动开启,可通过Shark.startTcpChannel()手动开启。
boolean autoStartTcpChannel = true;

// 创建一个Shark实例
Shark shark = SharkFactory.builder(context) // 必填
        .logEnable(IS_LOG_ENABLE)           // 选填,默认为false
        .sharkPkg(sharkPkg).instanceName(instanceName)  // 必填
        .sharkOutlet(sharkOutlet)                       // 必填
        .serviceFactory(serviceFactory)                 // 必填
        .withTcpChannel(withTcpChannel)                 // 必填
        .build();
// 启动Shark
shark.start(autoStartTcpChannel);

在应用进入前台时自动启动TCP长连接通道

进入前台自动启动TCP长连接可以在进入前台时触发自有通道推送,建议您开启。

//监听ActivityLifecycleCallbacks,进入前台后自动开启半长连接
monitorActivity(app, shark);
/**
 * 在进入前台界面的时候开启半长连接(如果此时未连接则会触发连接建立),
 * 会增加流量消耗,但可以在进入前台界面的时候触发推送,
 * 请根据业务需要自行判断是否需要
 */
private static void monitorActivity(Application application, final IShark shark) {
    if (application == null || shark == null) {
        return;
    }

    application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

        }

        @Override
        public void onActivityStarted(Activity activity) {
            Log.i("SharkService", "[shark_tcp_status]onActivityStarted, startTcpChannel, " + activity);
            shark.startTcpChannel();
        }

        @Override
        public void onActivityResumed(Activity activity) {

        }

        @Override
        public void onActivityPaused(Activity activity) {

        }

        @Override
        public void onActivityStopped(Activity activity) {

        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

        }

        @Override
        public void onActivityDestroyed(Activity activity) {

        }
    });
}

将Shark实例设置给基础库

初始化基础库时,将创建的shark实例设置给TMFBaseConfig。

TMFBaseConfig config = new TMFBaseConfig.Builder()  
    .shark(shark) //必须
        .build();  
TMFBase.init(application, config);

网关接入测试

  1. 获取guid,如果成功获取guid则表示接入成功。
    TMFBase.getShark().getGuidAsyn(new IGuidCallback() {
        @Override
        public void onCallback(int retCode, String guid) {
            if (!TextUtils.isEmpty(guid)) {
                Log.d("TMFDemo_test", "guid: " + guid + " 获取成功!!!!");
            } else {
                Log.d("TMFDemo_test", "获取GUID失败,guid: " + guid + " retCode: " + retCode);
            }
        }
    });
    
  2. 参考发起HTTP API请求 ,完成API请求测试。

TCP/HTTP双通道收发数据

TMF移动网关支持HTTP/TCP双通道收发数据,TCP通道效率更高且支持自有通道数据推送,HTTP通道更稳定可靠。建议您同时开启双通道收发数据。

TCP通道开启

内置Shark实例默认开启了TCP通道,非内置Shark实例开启方法请参见创建shark实例

使用默认标记发送请求

使用默认标记发送请求会优先选择TCP通道,建议您使用默认标记发送请求。

shark.sendHttpEntity(req, SharkCommonConst.DEFAULT, callback, 100000);

TCP通道大小限制

由于TCP通道是串行通道,在设计之初就不建议发送大数据包,否则容易引起请求阻塞,当请求包或者回包大小超过1MB时,需改用HTTP通道发送请求。

关闭TCP通道

在某些特定网络环境下,您的TCP通道无法正常工作,比较常见的原因是您的WAF设备不支持TCP通道。这种情况下建议您关闭TCP通道,只保留HTTP单通道运行。 关闭方法请参考TCP通道开启与关闭

开启TCP通道IP透传

在某些特定网络环境下,您可能无法通过TCP通道获取到真实的客户端IP,如果您遇到该问题,通常有两种解决办法:

  1. 通过TOA选项配置实现客户端透传,具体方法请参见 TOA实现客户端真实IP透传
  2. 通过客户端IP透传功能上报真实客户端IP,具体开启方法请参见开启TCP通道IP透传

开启IPv6

Shark HTTP通道使用的是系统API, 因此双栈支持依赖系统底层API实现,无需做特殊处理。TCP通道双栈实现采用的是赛马机制,v6和v4在一定延迟规则下并发连接,优先连接成功的会被采用。由于双栈模式性能一定下降,所以默认是关闭的。如果需要开启IPv6,请参见开启TCP通道IPv6

切换应用配置数据迁移规则

从基线1.8.0起(shark 3.x以上版本)TMF支持按照环境隔离框架数据,不同应用配置的框架数据会存储在独立的数据目录中互不影响。由于旧版Shark无法自动检测当前运行环境变化情况,需要您根据实际情况来指定数据迁移规则。具体设置方法请参见切换应用配置数据迁移规则

常见错误码

请参见Android常见错误码

Copyright © 2013-2023 Tencent Cloud. all right reserved,powered by GitbookUpdate Time 2023-08-31 14:46:07

results matching ""

    No results matching ""