NextCLi.com 帮助文档
香港CN2服务器跳板机系统被墙域名再次穿墙宝塔纯净版TRX靓号
  • 独立服务器
    • 🇭🇰香港VPS
    • 🇭🇰香港服务器
    • 🇺🇸美国服务器
    • 🇭🇰跳板机/堡垒机/Jump Server
  • 跳板机 NextCLi JumpServer
    • NextCLi跳板机介绍
    • 资产列表
    • 远程连接 Windows
    • 远程连接 Linux SSH
    • 子账号分配服务器资源
    • 授权凭证
    • 动态指令
    • 接入网关
    • 跳板机安全设置
    • 如何为NextCLi跳板机绑定域名
    • 跳板机读取剪贴板/复制/粘贴
    • 👍购买跳板机服务器
    • NextCLi跳板机找回密码
  • TRX/TRC20靓号地址
    • Trx-Trc20靓号地址USDT/USDC
  • 云平台 Cloud.NextCLi.com
    • 平台介绍
    • 账户
    • 充值/支付
    • 通知/Telegram通知/邮件通知
    • Telegram BOT机器人
      • Telegram客服机器人
      • Telegram群管理机器人
      • 加密货币监控机器人
    • App打包
    • 域名SSL证书
    • AI
      • LLM-API
  • 其他文档
    • 服务条款 Terms Of Service
    • 本站资源
由 GitBook 提供支持
在本页
  • 一、APP打包
  • 二、流量控制 https://cloud.nextcli.com/app/whitelist
  • 三、流量套餐 https://cloud.nextcli.com/app/plugin
  • 四、开发者文档
  1. 云平台 Cloud.NextCLi.com

App打包

APP打包封装 https://cloud.nextcli.com/app/package

上一页加密货币监控机器人下一页域名SSL证书

最后更新于4个月前

App 应用打包使用说明

本服务可将任何网站 URL 打包为 Android 与 Windows 应用(iOS、Mac 版本正在开发中),并在应用内部集成了防屏蔽功能,使海内外用户均可自由访问目标网站,不受防火墙限制。

同时,您也可以在此生成并下载专用的 Android 与 Windows 防屏蔽 SDK,将其整合至您的 App,以便突破网络访问限制。以下示例以 X(推特) 为例,展示如何使用本功能。

一、APP打包

1.1 创建APP

字段
说明

APP包名/APP ID

? 是APP的唯一ID,通常以 com.开头,如: com.example.myapp 不建议使用主流APP的名字,包名冲突,会覆盖已安装的同包名ID的APP;

APP适用系统

普通用户可选择打包Android APK、Windows EXE; 安卓AAR、Windows DLL 则是面向专业开发者的SDK。

APP主页链接

打开APP时,主页显示内容所在的链接网址;

APP图标

APP安装在桌面上显示的图标; Android推荐使用 512×512px 的图标以获得最佳效果; Windows同样512×512px 的图标,也可以直接使用网站的favicon.ico链接。

1.2. 打包与下载

  • 点击“打包”后,预计 1~5 分钟完成。需手动刷新查看进度。

  • 打包产物下载链接有效期为 1小时,过期后需重新打包。

  • 如果打包失败,请检查错误提示;如无法解决可联系客服。

1.3. 其他说明

  • 新用户在创建第一个应用后,可获得 1年 的每月 1G 流量套餐。

二、流量控制

2.1 流量加速

  • 开启流量加速后,白名单中的域名将启用防屏蔽功能。

  • 如果当月流量用完,需要再次购买套餐或流量包才能继续使用流量加速。

2.2 什么是加速白名单?

  • 流量加速开启后,白名单中的域名会通过加速通道,消耗套餐流量;其他域名则使用普通网络。

  • 创建应用后,系统会自动将应用主页链接的域名加入到加速白名单。

    例如,若应用主页链接为 abc.x.com,则默认将 abc.x.com 添加到白名单。

  • 您还可以手动添加更多域名到白名单,例如添加 123.x.com 、www.google.com,则该域名流量将走加速通道。

2.3 白名单规则

  1. 仅可添加域名(不能包含 http 或 https)。

  2. 若添加一级域名(如 x.com),其所有二级或子域名(如 m.x.com, www.x.com)皆自动纳入白名单。

  3. 若只添加二级域名(如 m.x.com),则不包含 x.com。

  • 新用户创建第一个应用后,系统会免费提供 1年 的每月 1G 流量套餐。

  • 您可多次购买同一套餐,后购买的套餐将覆盖之前的套餐,同时重置 App 的流量用量和到期时间。

  • ⚠️注意,必须先拥有一个套餐,才能购买流量包。流量包的有效期与当月套餐同步。

  • 如需更多套餐选项,请联系客服。

四、开发者文档

4.1 生成AAR

  1. 在创建应用时选择 AAR 作为目标产物,主页链接可先填后端 API 地址(后续可于白名单中修改)。

  2. 打包产物解压后将获得 checksum 文件与 xxx.aar 文件。

  3. sdk调用前需要把checksum复制到app的内部存储文件夹下,因为sdk需要校验这个文件,然后初始化sdk,参考以下demo

// kotlin 示例
CoroutineScope(Dispatchers.IO).launch {
    try {
        moveAssetsFileToInternalStorage(context, "checksum")

        // code=1 正常启动
        // 这里sdk工作目录必须和checksum文件在同一个目录
        val errCode = Safetunnel.newInstance(context.filesDir.absolutePath)

        // code=1 正常启动
        val startCode = Safetunnel.start()

        // 获取代理端口,应用层流量转发到这个端口即可使用流量加速功能
        val port = Safetunnel.getPort()
    } catch (e: Exception) {
        // log
    }

// Android复制assets文件到内部存储
private suspend fun moveAssetsFileToInternalStorage(
    context: Context,
    fileName: String
): Boolean {
    return withContext(Dispatchers.IO) {
        var inputStream: InputStream? = null
        try {
            inputStream = context.assets.open(fileName)
            // ⚠️注意:sdk工作目录必须和checksum文件在同一个目录
            val outFile = File(context.filesDir, fileName).apply {
                parentFile?.mkdirs()
            }
            if (!outFile.exists()) {
                // 将文件内容从输入流复制到输出流
                inputStream.copyTo(outFile.outputStream())
                Log.d(
                    "TAG",
                    "File $fileName moved to internal storage: ${outFile.absolutePath}"
                )
            }
            true
        } catch (e: Exception) {
            Log.e("TAG", "Failed to move file $fileName to internal storage: ${e.message}")
            false
        } finally {
            // 关闭流
            inputStream?.close()
        }
    }
}
  // java 示例
  new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            // 将 assets 文件移动到内部存储
            boolean isMoved = moveAssetsFileToInternalStorage(context, "checksum");
            if (!isMoved) {
                Log.e(TAG, "Failed to move checksum file.");
                return;
            }

            // ⚠️注意:SDK 工作目录必须和 checksum 文件在同一个目录
            int errCode = Safetunnel.newInstance(context.getFilesDir().getAbsolutePath());
            if (errCode != 1) {
                Log.e(TAG, "Safetunnel.newInstance failed with code: " + errCode);
                return;
            }

            // 启动 Safetunnel
            int startCode = Safetunnel.start();
            if (startCode != 1) {
                Log.e(TAG, "Safetunnel.start failed with code: " + startCode);
                return;
            }

            // 获取代理端口,应用层流量转发到这个端口即可使用流量加速功能
            int port = Safetunnel.getPort();
            Log.d(TAG, "Proxy port: " + port);

        } catch (Exception e) {
            Log.e(TAG, "Exception occurred: " + e.getMessage());
        }
    }
}).start();

// Android复制assets文件到内部存储,java示例
public static boolean moveAssetsFileToInternalStorage(Context context, String fileName) {
    InputStream inputStream = null;
    try {
        inputStream = context.getAssets().open(fileName);
        // 注意:SDK工作目录必须和checksum文件在同一个目录
        File outFile = new File(context.getFilesDir(), fileName);
        File parentDir = outFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }
        if (!outFile.exists()) {
            // 将文件内容从输入流复制到输出流
            try (FileOutputStream outputStream = new FileOutputStream(outFile)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = inputStream.read(buffer)) > 0) {
                    outputStream.write(buffer, 0, length);
                }
            }
            Log.d(TAG, "File " + fileName + " moved to internal storage: " + outFile.getAbsolutePath());
        }
        return true;
    } catch (Exception e) {
        Log.e(TAG, "Failed to move file " + fileName + " to internal storage: " + e.getMessage());
        return false;
    } finally {
        // 关闭输入流
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (Exception e) {
                Log.e(TAG, "Failed to close input stream: " + e.getMessage());
            }
        }
    }
}
// C#复制assets文件到内部存储
private string cachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "com.safelink.test", "Cache");

// 导入dll
[DllImport("libcore.dll")]
private static extern int NewInstance(string dir);

[DllImport("libcore.dll")]
private static extern int Start();

[DllImport("libcore.dll")]
private static extern int GetPort();

 private async void initSdk()
  {
      String filePath = Path.Combine(cachePath, "file");
      if (!Directory.Exists(filePath))
      {
          Directory.CreateDirectory(filePath);
      }
      if (!File.Exists(Path.Combine(filePath, "checksum")))
      {
          ExtractResourceToFile("pack://application:,,,/tmp/checksum", Path.Combine(filePath, "checksum"));
      }
      try
      {
          var ErrCode = NewInstance(filePath);
          Debug.WriteLine("NewInstance ErrCode:"+ ErrCode);
          if (ErrCode == 1)
          {
              ErrCode=Start();
              Debug.WriteLine("Start ErrCode:" + ErrCode);
          }
      }
      catch (Exception ex)
      {
          Debug.WriteLine("initSdk error:" + ex.ToString());
      }
  }

// 复制文件到内部存储
public static void ExtractResourceToFile(string resourceName, string filepath)
{
    try
    {
        // 获取当前程序集

        StreamResourceInfo info = Application.GetContentStream(new Uri(resourceName));

        // 使用资源名称从程序集获取资源流
        using (Stream resourceStream = info.Stream)
        {
            if (resourceStream == null)
            {
                throw new InvalidOperationException("Could not find resource: " + resourceName);
            }

            // 创建目标文件路径的目录
            Directory.CreateDirectory(Path.GetDirectoryName(filepath));

            // 创建文件流并写入从程序集提取的数据
            using (FileStream fileStream = new FileStream(filepath, FileMode.Create, FileAccess.Write))
            {
                resourceStream.CopyTo(fileStream);
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error extracting resource: " + ex.Message);
    }
}

  1. 应用层示例,这里以网络请求为例,更多使用示例请查看demo;

# Android kotlin 示例
val proxy =
    Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", Safetunnel.getPort()))
okHttpClient.proxy(proxy)
# Windows C# 示例
// 创建一个 HttpClientHandler,并设置代理信息
var httpClientHandler = new HttpClientHandler
{
    Proxy = new WebProxy("127.0.0.1:"+GetPort()),
    UseProxy = true,
};

// 使用 HttpClientHandler 创建 HttpClient
using (var httpClient = new HttpClient(httpClientHandler))
{
    // 发送 HTTP GET 请求
    HttpResponseMessage response = await httpClient.GetAsync("http://example.com");

    if (response.IsSuccessStatusCode)
    {
        // 处理成功响应
        string content = await response.Content.ReadAsStringAsync();
        Console.WriteLine(content);
    }
    else
    {
        // 处理错误响应
        Console.WriteLine($"HTTP Error: {response.StatusCode}");
    }
}


参考链接

三、流量套餐

完整示例可查看 。

•

•

https://cloud.nextcli.com/app/package
https://cloud.nextcli.com/app/whitelist
https://cloud.nextcli.com/app/plugin
GitHub 项目
Android 开发者文档(英文)
Windows 应用打包(Microsoft 官方文档)