Small插件化

本文介绍如何使用Small框架进行插件化开发,并实现热修复功能。通过配置Gradle插件和bundles.json文件,实现模块化管理和远程更新So文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Small 的集成异常简单,只需要在项目下的 build.gradle 文件dependencies 中添加 Small 编译插件 gradle-small:

classpath 'net.wequick.tools.build:gradle-small:1.3.0-beta2'
复制代码

并且在文件末尾引用插件:

apply plygin: 'net.wequick.small'
复制代码

但 Small 对于项目结构的要求比较严格,比如宿主最好就是刚开始新建项目时候的 app 应用,这个名字最好不要改,Small 会通过名字来寻找宿主和插件。插件业务模块命名以 app.* 和lib.* 作开头,包名最好也要以 app.或者 app 结尾,插件业务模块都是可以单独打包的模块,这些模块和 app 一样.

然后在/assets/bundle.json文件中注册自己的所有模块

{
  "version": "1.0.0",
  "bundles": [
    {
      "uri": "lib.utils",
      "pkg": "net.wequick.example.small.lib.utils"
    },
    {
      "uri": "lib.style",
      "pkg": "com.example.mysmall.lib.style"
    },
    {
      "uri": "lib.analytics",
      "pkg": "net.wequick.example.lib.analytics"
    },
    {
      "uri": "main",
      "pkg": "net.wequick.example.small.app.main"
    },
    {
      "uri": "home",
      "pkg": "net.wequick.example.small.app.home"
    },
    {
      "uri": "mine",
      "pkg": "net.wequick.example.small.app.mine"
    },
    {
      "uri": "detail",
      "pkg": "net.wequick.example.small.app.detail",
      "rules": {
        "sub": "Sub"
      }
    },
    {
      "uri": "stub",
      "type": "app",
      "pkg": "net.wequick.example.small.appok_if_stub"
    },
    {
      "uri": "about",
      "pkg": "net.wequick.example.small.web.about"
    }
  ]
}

复制代码

跳转其他Activity

默认的跳转是跳转到启动页面,传递参数的形式和GET请求一样

跳转指定的activity

先buildlib后buildBundle

small也可以实现热修复的功能

public class UpgradeManager {


  private static class UpdateInfo {
    public String packageName;
    public String downloadUrl;
  }

  private static class UpgradeInfo {
    public JSONObject manifest;
    public List<UpgradeManager.UpdateInfo> updates;
  }

  private interface OnResponseListener {
    void onResponse(UpgradeManager.UpgradeInfo info);
  }

  private interface OnUpgradeListener {
    void onUpgrade(boolean succeed);
  }

  private static class ResponseHandler extends Handler {
    private UpgradeManager.OnResponseListener mListener;

    public ResponseHandler(UpgradeManager.OnResponseListener listener) {
      mListener = listener;
    }

    @Override public void handleMessage(Message msg) {
      switch (msg.what) {
        case 1:
          mListener.onResponse((UpgradeManager.UpgradeInfo) msg.obj);
          break;
      }
    }
  }

  private UpgradeManager.ResponseHandler mResponseHandler;

  private Context mContext;
  private ProgressDialog mProgressDlg;

  public UpgradeManager(Context context) {
    mContext = context;
  }


 public void checkUpgrade() {
      //mProgressDlg = ProgressDialog.show(mContext, "Small", "Checking for updates...");
      requestUpgradeInfo(Small.getBundleVersions(), new OnResponseListener() {
        @Override public void onResponse(UpgradeInfo info) {
          //mProgressDlg.setMessage("Upgrading...");
          upgradeBundles(info, new OnUpgradeListener() {
            @Override public void onUpgrade(boolean succeed) {
              //mProgressDlg.dismiss();
              //mProgressDlg = null;
              String text = succeed
                  ? "Upgrade Success! Switch to background and back to foreground to see changes."
                  : "Upgrade Failed!";
              Log.i("tag", "===========" + text);
              Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
            }
          });
        }
      });
    }

  /**
   *
   * @param versions
   * @param listener
   */
  private void requestUpgradeInfo(Map versions, UpgradeManager.OnResponseListener listener) {
    System.out.println(versions); // this should be passed as HTTP parameters
    mResponseHandler = new UpgradeManager.ResponseHandler(listener);
    new Thread() {
      @Override public void run() {
        try {
          // 换成自己服务器地址
          // Json format see http://wequick.github.io/small/upgrade/bundles.json
          URL url = new URL("http://incoidea.incopat.com/appservice/resources/bundle.json");
          HttpURLConnection conn = (HttpURLConnection) url.openConnection();
          StringBuilder sb = new StringBuilder();
          InputStream is = conn.getInputStream();
          byte[] buffer = new byte[1024];
          int length;
          while ((length = is.read(buffer)) != -1) {
            sb.append(new String(buffer, 0, length));
          }

          // Parse json
          JSONObject jo = new JSONObject(sb.toString());
          JSONObject mf = jo.has("manifest") ? jo.getJSONObject("manifest") : null;
          JSONArray updates = jo.getJSONArray("updates");
          int N = updates.length();
          List<UpgradeManager.UpdateInfo> infos = new ArrayList<>(N);
          for (int i = 0; i < N; i++) {
            JSONObject o = updates.getJSONObject(i);
            UpgradeManager.UpdateInfo
                info = new UpgradeManager.UpdateInfo();
            info.packageName = o.getString("pkg");
            info.downloadUrl = o.getString("url");
            infos.add(info);
          }

          // Post message
          UpgradeManager.UpgradeInfo
              ui = new UpgradeManager.UpgradeInfo();
          ui.manifest = mf;
          ui.updates = infos;
          Message.obtain(mResponseHandler, 1, ui).sendToTarget();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }.start();
  }

  private static class DownloadHandler extends Handler {
    private UpgradeManager.OnUpgradeListener mListener;

    public DownloadHandler(UpgradeManager.OnUpgradeListener listener) {
      mListener = listener;
    }

    @Override public void handleMessage(Message msg) {
      switch (msg.what) {
        case 1:
          mListener.onUpgrade((Boolean) msg.obj);
          break;
      }
    }
  }

  private UpgradeManager.DownloadHandler mHandler;

  private void upgradeBundles(final UpgradeManager.UpgradeInfo info, final UpgradeManager.OnUpgradeListener listener) {
    // Just for example, you can do this by OkHttp or something.
    mHandler = new UpgradeManager.DownloadHandler(listener);
    new Thread() {
      @Override public void run() {
        try {
          // Update manifest
          if (info.manifest != null) {
            if (!Small.updateManifest(info.manifest, false)) {
              Message.obtain(mHandler, 1, false).sendToTarget();
              return;
            }
          }
          // Download bundles
          List<UpgradeManager.UpdateInfo> updates = info.updates;
          for (UpgradeManager.UpdateInfo u : updates) {
            // Get the patch file for downloading
            net.wequick.small.Bundle bundle = Small.getBundle(u.packageName);
            File file = bundle.getPatchFile();

            // Download
            URL url = new URL(u.downloadUrl);
            HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
            InputStream is = urlConn.getInputStream();
            OutputStream os = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = is.read(buffer)) != -1) {
              os.write(buffer, 0, length);
            }
            os.flush();
            os.close();
            is.close();

            // Upgrade
            bundle.upgrade();
          }

          Message.obtain(mHandler, 1, true).sendToTarget();
        } catch (IOException e) {
          e.printStackTrace();
          Message.obtain(mHandler, 1, false).sendToTarget();
        }
      }
    }.start();
  }
}

复制代码

上面这个类就实现了热修复的功能 把bundles.json放在你的服务器上 这里的url换成你自己的url

然后调用 new UpgradeManager(getContext()).checkUpgrade();就可以你的服务器下载最新的.so文件了

  private void requestUpgradeInfo(Map versions, UpgradeManager.OnResponseListener listener) {
    System.out.println(versions); // this should be passed as HTTP parameters
    mResponseHandler = new UpgradeManager.ResponseHandler(listener);
    new Thread() {
      @Override public void run() {
        try {
          // Example HTTP request to get the upgrade bundles information.
          // Json format see http://wequick.github.io/small/upgrade/bundles.json
          URL url = new URL("yourUrl");
          HttpURLConnection conn = (HttpURLConnection) url.openConnection();
          StringBuilder sb = new StringBuilder();
          InputStream is = conn.getInputStream();
          byte[] buffer = new byte[1024];
          int length;
          while ((length = is.read(buffer)) != -1) {
            sb.append(new String(buffer, 0, length));
          }

          // Parse json
          JSONObject jo = new JSONObject(sb.toString());
          JSONObject mf = jo.has("manifest") ? jo.getJSONObject("manifest") : null;
          JSONArray updates = jo.getJSONArray("updates");
          int N = updates.length();
          List<UpgradeManager.UpdateInfo> infos = new ArrayList<>(N);
          for (int i = 0; i < N; i++) {
            JSONObject o = updates.getJSONObject(i);
            UpgradeManager.UpdateInfo
                info = new UpgradeManager.UpdateInfo();
            info.packageName = o.getString("pkg");
            info.downloadUrl = o.getString("url");
            infos.add(info);
          }

          // Post message
          UpgradeManager.UpgradeInfo
              ui = new UpgradeManager.UpgradeInfo();
          ui.manifest = mf;
          ui.updates = infos;
          Message.obtain(mResponseHandler, 1, ui).sendToTarget();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }.start();
  }

复制代码

bundles.json的书写规则

{
  "manifest": {
    "version": "1.0.0",
    "bundles": [
    {
      "uri": "lib.utils",
      "pkg": "net.wequick.example.small.lib.utils"
    },
    {
      "uri": "lib.style",
      "pkg": "com.example.mysmall.lib.style"
    },
    {
      "uri": "lib.analytics",
      "pkg": "net.wequick.example.lib.analytics"
    },
    {
      "uri": "main",
      "pkg": "net.wequick.example.small.app.main"
    },
    {
      "uri": "home",
      "pkg": "net.wequick.example.small.app.home"
    },
    {
      "uri": "mine",
      "pkg": "net.wequick.example.small.app.mine"
    },
    {
      "uri": "detail",
      "pkg": "net.wequick.example.small.app.detail",
      "rules": {
        "sub": "Sub"
      }
    },
    {
      "uri": "stub",
      "type": "app",
      "pkg": "net.wequick.example.small.appok_if_stub"
    },
    {
      "uri": "about",
      "pkg": "net.wequick.example.small.app.about"
    }
  ]
  },
  "updates": [
    {
      "pkg": "net.wequick.example.small.app.about",
      "url": "http://wequick.github.io/small/upgrade/libnet_wequick_example_small_app_about.so"
    },
    {
      "pkg": "net.wequick.example.small.lib.utils",
      "url": "http://wequick.github.io/small/upgrade/libnet_wequick_example_small_lib_utils.so"
    },
    {
      "pkg": "com.example.mysmall.lib.style",
      "url": "http://wequick.github.io/small/upgrade/libcom_example_mysmall_lib_style.so"
    },
    {
      "pkg": "net.wequick.example.small.app.home",
      "url": "http://wequick.github.io/small/upgrade/libnet_wequick_example_small_app_home.so"
    }
  ]
}

复制代码

看到这我们发现bundles的第一个标签是 manifest ,从上面代码发现当我们从服务器获取到bundles.json文件时 就去解析文件内容,解析到***manifest***标签的时候 ,开始修改***AndroidMainfes***文件,从而达到更新***AndroidMainfest*** 文件

再来看bundles.json文件 ***updates***标签 这里面 pkg 对应的是我们插件的包名 ***url***则对应的是我们服务器上对应的.So文件的地址,拿到.So文件的地址,就去下载并替换原有的.So文件,从而达到热修复的作用。

其实Small还不能说是热修复,因为当So文件被替换修改的时候需要退出应用,再次进去入才能有效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值