コード例 #1
0
  /**
   * 构造插件信息
   *
   * @param
   */
  static void ensurePluginInited(PluginDescriptor pluginDescriptor) {
    if (pluginDescriptor != null) {
      DexClassLoader pluginClassLoader = pluginDescriptor.getPluginClassLoader();
      if (pluginClassLoader == null) {
        LogUtil.d("正在初始化插件Resources, DexClassLoader, Context, Application ");

        LogUtil.d("是否为独立插件", pluginDescriptor.isStandalone());

        Resources pluginRes =
            PluginCreator.createPluginResource(
                sApplication, pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone());

        pluginClassLoader =
            PluginCreator.createPluginClassLoader(
                pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone());
        Context pluginContext =
            PluginCreator.createPluginApplicationContext(
                pluginDescriptor, sApplication, pluginRes, pluginClassLoader);

        pluginContext.setTheme(sApplication.getApplicationContext().getApplicationInfo().theme);
        pluginDescriptor.setPluginContext(pluginContext);
        pluginDescriptor.setPluginClassLoader(pluginClassLoader);

        // 使用了openAtlasExtention之后就不需要Public.xml文件了
        // checkPluginPublicXml(pluginDescriptor, pluginRes);

        callPluginApplicationOnCreate(pluginDescriptor);

        LogUtil.d("初始化插件" + pluginDescriptor.getPackageName() + "完成");
      }
    }
  }
コード例 #2
0
  /**
   * 构造插件信息
   *
   * @param
   */
  static void ensurePluginInited(PluginDescriptor pluginDescriptor) {
    if (pluginDescriptor != null) {
      DexClassLoader pluginClassLoader = pluginDescriptor.getPluginClassLoader();
      if (pluginClassLoader == null) {
        LogUtil.e(
            "正在初始化插件"
                + pluginDescriptor.getPackageName()
                + "Resources, DexClassLoader, Context, Application");

        LogUtil.d("是否为独立插件", pluginDescriptor.isStandalone());

        Resources pluginRes = PluginCreator.createPluginResource(sApplication, pluginDescriptor);

        pluginClassLoader =
            PluginCreator.createPluginClassLoader(
                pluginDescriptor.getInstalledPath(),
                pluginDescriptor.isStandalone(),
                pluginDescriptor.getDependencies());
        Context pluginContext =
            PluginCreator.createPluginContext(
                pluginDescriptor, sApplication, pluginRes, pluginClassLoader);

        // 插件Context默认主题设置为插件application主题
        pluginContext.setTheme(pluginDescriptor.getApplicationTheme());
        pluginDescriptor.setPluginContext(pluginContext);
        pluginDescriptor.setPluginClassLoader(pluginClassLoader);

        try {
          ActivityThread.installPackageInfo(getApplicatoin(), pluginDescriptor.getPackageName());
        } catch (ClassNotFoundException e) {
          e.printStackTrace();
        }

        callPluginApplicationOnCreate(pluginDescriptor);

        LogUtil.e("初始化插件" + pluginDescriptor.getPackageName() + "完成");
      }
    }
  }
コード例 #3
0
  /**
   * 安装一个插件
   *
   * @param srcPluginFile
   * @return
   */
  public static synchronized int installPlugin(String srcPluginFile) {
    LogUtil.e("开始安装插件", srcPluginFile);
    if (TextUtils.isEmpty(srcPluginFile) || !new File(srcPluginFile).exists()) {
      return SRC_FILE_NOT_FOUND;
    }

    // 第0步,先将apk复制到宿主程序私有目录,防止在安装过程中文件被篡改
    if (!srcPluginFile.startsWith(sApplication.getCacheDir().getAbsolutePath())) {
      String tempFilePath =
          sApplication.getCacheDir().getAbsolutePath()
              + File.separator
              + System.currentTimeMillis()
              + ".apk";
      if (FileUtil.copyFile(srcPluginFile, tempFilePath)) {
        srcPluginFile = tempFilePath;
      } else {
        LogUtil.e("复制插件文件失败", srcPluginFile, tempFilePath);
        return COPY_FILE_FAIL;
      }
    }

    // 第1步,验证插件APK签名,如果被篡改过,将获取不到证书
    // sApplication.getPackageManager().getPackageArchiveInfo(srcPluginFile,
    // PackageManager.GET_SIGNATURES);
    Signature[] pluginSignatures = PackageVerifyer.collectCertificates(srcPluginFile, false);
    boolean isDebugable =
        (0 != (sApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE));
    if (pluginSignatures == null) {
      LogUtil.e("插件签名验证失败", srcPluginFile);
      new File(srcPluginFile).delete();
      return SIGNATURES_INVALIDATE;
    } else if (NEED_VERIFY_CERT && !isDebugable) {
      // 可选步骤,验证插件APK证书是否和宿主程序证书相同。
      // 证书中存放的是公钥和算法信息,而公钥和私钥是1对1的
      // 公钥相同意味着是同一个作者发布的程序
      Signature[] mainSignatures = null;
      try {
        PackageInfo pkgInfo =
            sApplication
                .getPackageManager()
                .getPackageInfo(sApplication.getPackageName(), PackageManager.GET_SIGNATURES);
        mainSignatures = pkgInfo.signatures;
      } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
      }
      if (!PackageVerifyer.isSignaturesSame(mainSignatures, pluginSignatures)) {
        LogUtil.e("插件证书和宿主证书不一致", srcPluginFile);
        new File(srcPluginFile).delete();
        return VERIFY_SIGNATURES_FAIL;
      }
    }

    // 第2步,解析Manifest,获得插件详情
    PluginDescriptor pluginDescriptor = PluginManifestParser.parseManifest(srcPluginFile);
    if (pluginDescriptor == null || TextUtils.isEmpty(pluginDescriptor.getPackageName())) {
      LogUtil.e("解析插件Manifest文件失败", srcPluginFile);
      new File(srcPluginFile).delete();
      return PARSE_MANIFEST_FAIL;
    }

    PackageInfo packageInfo =
        sApplication
            .getPackageManager()
            .getPackageArchiveInfo(srcPluginFile, PackageManager.GET_GIDS);
    if (packageInfo != null) {
      pluginDescriptor.setApplicationTheme(packageInfo.applicationInfo.theme);
      pluginDescriptor.setApplicationIcon(packageInfo.applicationInfo.icon);
      pluginDescriptor.setApplicationLogo(packageInfo.applicationInfo.logo);
    }

    boolean isNeedPending = false;
    // 第3步,检查插件是否已经存在,若存在删除旧的
    PluginDescriptor oldPluginDescriptor =
        getPluginDescriptorByPluginId(pluginDescriptor.getPackageName());
    if (oldPluginDescriptor != null) {
      LogUtil.e(
          "已安装过,安装路径为",
          oldPluginDescriptor.getInstalledPath(),
          oldPluginDescriptor.getVersion(),
          pluginDescriptor.getVersion());

      // 检查插件是否已经加载
      if (oldPluginDescriptor.getPluginContext() != null) {
        if (!oldPluginDescriptor.getVersion().equals(pluginDescriptor.getVersion())) {
          LogUtil.e("旧版插件已经加载, 且新版插件和旧版插件版本不同,进入pending状态,新版插件将在安装后进程重启再生效");
          isNeedPending = true;
        } else {
          LogUtil.e("旧版插件已经加载, 且新版插件和旧版插件版本相同,拒绝安装");
          new File(srcPluginFile).delete();
          return FAIL_BECAUSE_HAS_LOADED;
        }
      } else {
        LogUtil.e("旧版插件还未加载,忽略版本,直接删除旧版,尝试安装新版");
        remove(oldPluginDescriptor.getPackageName());
      }
    }

    // 第4步骤,复制插件到插件目录
    String destApkPath =
        pluginManager.genInstallPath(
            pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
    boolean isCopySuccess = FileUtil.copyFile(srcPluginFile, destApkPath);

    if (!isCopySuccess) {

      LogUtil.e("复制插件到安装目录失败", srcPluginFile);
      // 删掉临时文件
      new File(srcPluginFile).delete();
      return COPY_FILE_FAIL;
    } else {

      // 第5步,先解压so到临时目录,再从临时目录复制到插件so目录。 在构造插件Dexclassloader的时候,会使用这个so目录作为参数
      File apkParent = new File(destApkPath).getParentFile();
      File tempSoDir = new File(apkParent, "temp");
      Set<String> soList = FileUtil.unZipSo(srcPluginFile, tempSoDir);
      if (soList != null) {
        for (String soName : soList) {
          FileUtil.copySo(tempSoDir, soName, apkParent.getAbsolutePath());
        }
        // 删掉临时文件
        FileUtil.deleteAll(tempSoDir);
      }

      // 第6步 添加到已安装插件列表
      pluginDescriptor.setInstalledPath(destApkPath);
      boolean isInstallSuccess = false;
      if (!isNeedPending) {
        isInstallSuccess = pluginManager.addOrReplace(pluginDescriptor);
      } else {
        isInstallSuccess = pluginManager.pending(pluginDescriptor);
      }
      // 删掉临时文件
      new File(srcPluginFile).delete();

      if (!isInstallSuccess) {
        LogUtil.e("安装插件失败", srcPluginFile);

        new File(destApkPath).delete();

        return INSTALL_FAIL;
      } else {
        // 通过创建classloader来触发dexopt,但不加载
        LogUtil.d("正在进行DEXOPT...", pluginDescriptor.getInstalledPath());
        FileUtil.deleteAll(new File(apkParent, "dalvik-cache"));
        PluginCreator.createPluginClassLoader(
            pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone(), null);
        LogUtil.d("DEXOPT完毕");

        if (!isNeedPending) {
          LocalServiceManager.registerService(pluginDescriptor);
        }

        changeListener.onPluginInstalled(
            pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
        LogUtil.e("安装插件成功," + (isNeedPending ? " 重启进程生效" : " 立即生效"), destApkPath);

        return SUCCESS;
      }
    }
  }