/**
   * //If getComponent returns an explicit class, that is returned without any further
   * consideration. //If getAction is non-NULL, the activity must handle this action. //If
   * resolveType returns non-NULL, the activity must handle this type. //If addCategory has added
   * any categories, the activity must handle ALL of the categories specified. //If getPackage is
   * non-NULL, only activity components in that application package will be considered.
   *
   * @param intent
   * @return
   */
  public static String matchPlugin(Intent intent) {

    Iterator<PluginDescriptor> itr = getPlugins().iterator();

    while (itr.hasNext()) {
      PluginDescriptor plugin = itr.next();
      // 如果是通过组件进行匹配的
      if (intent.getComponent() != null) {
        if (plugin.containsName(intent.getComponent().getClassName())) {
          return intent.getComponent().getClassName();
        }
      } else {
        // 如果是通过IntentFilter进行匹配的
        String clazzName = findClassNameByIntent(intent, plugin.getActivitys());

        if (clazzName == null) {
          clazzName = findClassNameByIntent(intent, plugin.getServices());
        }

        if (clazzName == null) {
          clazzName = findClassNameByIntent(intent, plugin.getReceivers());
        }

        if (clazzName != null) {
          return clazzName;
        }
      }
    }
    return null;
  }
  private void listAll() {
    ViewGroup root = mList;
    root.removeAllViews();

    // 列出所有已经安装的插件
    Collection<PluginDescriptor> plugins = PluginLoader.getPlugins();
    Iterator<PluginDescriptor> itr = plugins.iterator();
    while (itr.hasNext()) {
      final PluginDescriptor pluginDescriptor = itr.next();
      Button button = new Button(this);
      button.setPadding(10, 10, 10, 10);
      button.setText("插件id:" + pluginDescriptor.getPackageName() + ",点击查看");
      button.setOnClickListener(
          new View.OnClickListener() {

            @Override
            public void onClick(View v) {
              Intent intent = new Intent(PluginListActivity.this, PluginDetailActivity.class);
              intent.putExtra("plugin_id", pluginDescriptor.getPackageName());
              startActivity(intent);
            }
          });

      LayoutParams layoutParam =
          new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
      layoutParam.topMargin = 10;
      layoutParam.bottomMargin = 10;
      layoutParam.gravity = Gravity.LEFT;
      root.addView(button, layoutParam);
    }
  }
  /**
   * 获取目标类型,activity or service or broadcast
   *
   * @param intent
   * @return
   */
  public static int getTargetType(Intent intent) {

    Iterator<PluginDescriptor> itr = getPlugins().iterator();

    while (itr.hasNext()) {
      PluginDescriptor plugin = itr.next();
      // 如果是通过组件进行匹配的
      if (intent.getComponent() != null) {
        if (plugin.containsName(intent.getComponent().getClassName())) {
          return plugin.getType(intent.getComponent().getClassName());
        }
      } else {
        String clazzName = findClassNameByIntent(intent, plugin.getActivitys());

        if (clazzName == null) {
          clazzName = findClassNameByIntent(intent, plugin.getServices());
        }

        if (clazzName == null) {
          clazzName = findClassNameByIntent(intent, plugin.getReceivers());
        }

        if (clazzName != null) {
          return plugin.getType(clazzName);
        }
      }
    }
    return PluginDescriptor.UNKOWN;
  }
 public static boolean isInstalled(String pluginId, String pluginVersion) {
   PluginDescriptor pluginDescriptor = getPluginDescriptorByPluginId(pluginId);
   if (pluginDescriptor != null) {
     return pluginDescriptor.getVersion().equals(pluginVersion);
   }
   return false;
 }
  @SuppressWarnings("rawtypes")
  public static Class loadPluginClassByName(String clazzName) {

    PluginDescriptor pluginDescriptor = getPluginDescriptorByClassName(clazzName);

    if (pluginDescriptor != null) {

      ensurePluginInited(pluginDescriptor);

      DexClassLoader pluginClassLoader = pluginDescriptor.getPluginClassLoader();

      try {
        Class pluginClazz = ((ClassLoader) pluginClassLoader).loadClass(clazzName);
        LogUtil.d("loadPluginClass Success for clazzName ", clazzName);
        return pluginClazz;
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (java.lang.IllegalAccessError illegalAccessError) {
        illegalAccessError.printStackTrace();
        throw new IllegalAccessError(
            "出现这个异常最大的可能是插件dex和" + "宿主dex包含了相同的class导致冲突, " + "请检查插件的编译脚本,确保排除了所有公共依赖库的jar");
      }
    }

    LogUtil.e("loadPluginClass Fail for clazzName ", clazzName);

    return null;
  }
  @SuppressWarnings("rawtypes")
  public static Class loadPluginClassByName(String clazzName) {

    PluginDescriptor pluginDescriptor = getPluginDescriptorByClassName(clazzName);

    if (pluginDescriptor != null) {

      ensurePluginInited(pluginDescriptor);

      DexClassLoader pluginClassLoader = pluginDescriptor.getPluginClassLoader();

      try {
        Class pluginClazz = ((ClassLoader) pluginClassLoader).loadClass(clazzName);
        LogUtil.d("loadPluginClass Success for clazzName ", clazzName);
        return pluginClazz;
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (java.lang.IllegalAccessError illegalAccessError) {
        illegalAccessError.printStackTrace();
      }
    }

    LogUtil.e("loadPluginClass Fail for clazzName ", clazzName);

    return null;
  }
  /**
   * 根据插件中的classId加载一个插件中的class
   *
   * @param clazzId
   * @return
   */
  @SuppressWarnings("rawtypes")
  public static Class loadPluginFragmentClassById(String clazzId) {

    PluginDescriptor pluginDescriptor = getPluginDescriptorByFragmenetId(clazzId);

    if (pluginDescriptor != null) {

      ensurePluginInited(pluginDescriptor);

      DexClassLoader pluginClassLoader = pluginDescriptor.getPluginClassLoader();

      String clazzName = pluginDescriptor.getPluginClassNameById(clazzId);
      if (clazzName != null) {
        try {
          Class pluginClazz = ((ClassLoader) pluginClassLoader).loadClass(clazzName);
          LogUtil.d("loadPluginClass for clazzId", clazzId, "clazzName", clazzName, "success");
          return pluginClazz;
        } catch (ClassNotFoundException e) {
          e.printStackTrace();
        }
      }
    }

    LogUtil.e("loadPluginClass for clazzId", clazzId, "fail");

    return null;
  }
  /**
   * 构造插件信息
   *
   * @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() + "完成");
      }
    }
  }
  private static void callPluginApplicationOnCreate(PluginDescriptor pluginDescriptor) {

    Application application = null;

    if (pluginDescriptor.getPluginApplication() == null
        && pluginDescriptor.getPluginClassLoader() != null) {
      try {
        LogUtil.d("创建插件Application", pluginDescriptor.getApplicationName());
        application =
            Instrumentation.newApplication(
                pluginDescriptor
                    .getPluginClassLoader()
                    .loadClass(pluginDescriptor.getApplicationName()),
                pluginDescriptor.getPluginContext());
        pluginDescriptor.setPluginApplication(application);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (InstantiationException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    }

    // 安装ContentProvider
    PluginInjector.installContentProviders(
        sApplication, pluginDescriptor.getProviderInfos().values());

    // 执行onCreate
    if (application != null) {
      application.onCreate();
    }

    changeListener.onPluginStarted(pluginDescriptor.getPackageName());
  }
 @TargetApi(Build.VERSION_CODES.GINGERBREAD)
 public static Drawable getLogo(PluginDescriptor pd) {
   PackageManager pm = PluginLoader.getApplication().getPackageManager();
   PackageInfo info =
       pm.getPackageArchiveInfo(pd.getInstalledPath(), PackageManager.GET_ACTIVITIES);
   if (info != null) {
     ApplicationInfo appInfo = info.applicationInfo;
     appInfo.sourceDir = pd.getInstalledPath();
     appInfo.publicSourceDir = pd.getInstalledPath();
     Drawable logo = pm.getApplicationLogo(appInfo);
     return logo;
   }
   return null;
 }
 private static Context newDefaultAppContext(PluginDescriptor pluginDescriptor) {
   Context newContext = null;
   if (pluginDescriptor != null && pluginDescriptor.getPluginContext() != null) {
     Context originContext = pluginDescriptor.getPluginContext();
     newContext =
         PluginCreator.createPluginContext(
             ((PluginContextTheme) originContext).getPluginDescriptor(),
             sApplication,
             originContext.getResources(),
             (DexClassLoader) originContext.getClassLoader());
     newContext.setTheme(pluginDescriptor.getApplicationTheme());
   }
   return newContext;
 }
  public static Context getDefaultPluginContext(String pluginId) {
    Context pluginContext = null;
    PluginDescriptor pluginDescriptor = getPluginDescriptorByPluginId(pluginId);

    if (pluginDescriptor != null) {
      pluginContext = pluginDescriptor.getPluginContext();
    } else {
      LogUtil.e("PluginDescriptor Not Found for ", pluginId);
    }

    if (pluginContext == null) {
      LogUtil.e("Context Not Found for ", pluginId);
    }

    return pluginContext;
  }
  /**
   * 获取当前class所在插件的Context 每个插件只有1个DefaultContext, 是当前插件中所有class公用的Context
   *
   * @param clazz
   * @return
   */
  public static Context getDefaultPluginContext(@SuppressWarnings("rawtypes") Class clazz) {

    Context pluginContext = null;
    PluginDescriptor pluginDescriptor = getPluginDescriptorByClassName(clazz.getName());

    if (pluginDescriptor != null) {
      pluginContext = pluginDescriptor.getPluginContext();
    } else {
      LogUtil.e("PluginDescriptor Not Found for ", clazz.getName());
    }

    if (pluginContext == null) {
      LogUtil.e("Context Not Found for ", clazz.getName());
    }

    return pluginContext;
  }
 public static String getLabel(PluginDescriptor pd) {
   PackageManager pm = PluginLoader.getApplication().getPackageManager();
   PackageInfo info =
       pm.getPackageArchiveInfo(pd.getInstalledPath(), PackageManager.GET_ACTIVITIES);
   if (info != null) {
     ApplicationInfo appInfo = info.applicationInfo;
     appInfo.sourceDir = pd.getInstalledPath();
     appInfo.publicSourceDir = pd.getInstalledPath();
     String label = null;
     try {
       if (!isMainResId(appInfo.labelRes)) {
         label = pm.getApplicationLabel(appInfo).toString();
       }
     } catch (Resources.NotFoundException e) {
     }
     if (label == null || label.equals(pd.getPackageName())) {
       // 可能设置的lable是来自宿主的资源
       if (pd.getDescription() != null) {
         int id = ResourceUtil.getResourceId(pd.getDescription());
         if (id != 0) {
           // 再宿主中查一次
           try {
             label = PluginLoader.getApplication().getResources().getString(id);
           } catch (Resources.NotFoundException e) {
           }
         }
       }
     }
     if (label != null) {
       return label;
     }
   }
   return pd.getDescription();
 }
  /**
   * for eclipse & ant with public.xml
   *
   * <p>unused
   *
   * @param pluginDescriptor
   * @param res
   * @return
   */
  private static boolean checkPluginPublicXml(PluginDescriptor pluginDescriptor, Resources res) {

    // "plugin_layout_1"资源id时由public.xml配置的
    // 如果没有检测到这个资源,说明编译时没有引入public.xml,
    // 这里直接抛个异常出去。
    // 不同的系统版本获取id的方式不同,
    // 三星4.x等系统适用
    int publicStub =
        res.getIdentifier("plugin_layout_1", "layout", pluginDescriptor.getPackageName());
    if (publicStub == 0) {
      // 小米5.x等系统适用
      publicStub = res.getIdentifier("plugin_layout_1", "layout", sApplication.getPackageName());
    }
    if (publicStub == 0) {
      try {
        // 如果以上两种方式都检测失败,最后尝试通过反射检测
        Class layoutClass =
            ((ClassLoader) pluginDescriptor.getPluginClassLoader())
                .loadClass(pluginDescriptor.getPackageName() + ".R$layout");
        Integer layouId = (Integer) RefInvoker.getFieldObject(null, layoutClass, "plugin_layout_1");
        if (layouId != null) {
          publicStub = layouId;
        }
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      }
    }

    if (publicStub == 0) {
      throw new IllegalStateException(
          "\n插件工程没有使用public.xml给资源id分组!!!\n"
              + "插件工程没有使用public.xml给资源id分组!!!\n"
              + "插件工程没有使用public.xml给资源id分组!!!\n"
              + "重要的事情讲三遍!!!");
    }
    return true;
  }
  public static ArrayList<String> matchPlugin(Intent intent, int type) {
    ArrayList<String> result = null;

    String packageName = intent.getPackage();
    if (packageName == null && intent.getComponent() != null) {
      packageName = intent.getComponent().getPackageName();
    }
    if (packageName != null
        && !packageName.equals(PluginLoader.getApplicatoin().getPackageName())) {
      PluginDescriptor dp = getPluginDescriptorByPluginId(packageName);
      if (dp != null) {
        List<String> list = dp.matchPlugin(intent, type);
        if (list != null && list.size() > 0) {
          if (result == null) {
            result = new ArrayList<>();
          }
          result.addAll(list);
        }
      }
    } else {
      Iterator<PluginDescriptor> itr = getPlugins().iterator();
      while (itr.hasNext()) {
        List<String> list = itr.next().matchPlugin(intent, type);
        if (list != null && list.size() > 0) {
          if (result == null) {
            result = new ArrayList<>();
          }
          result.addAll(list);
        }
        if (result != null && type != PluginDescriptor.BROADCAST) {
          break;
        }
      }
    }
    return result;
  }
  /**
   * 安装一个插件
   *
   * @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;
      }
    }
  }
  /**
   * 安装一个插件
   *
   * @param srcPluginFile
   * @return
   */
  public static synchronized int installPlugin(String srcPluginFile) {
    LogUtil.d("开始安装插件", 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 = ManifestParser.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);
    pluginDescriptor.setApplicationTheme(packageInfo.applicationInfo.theme);
    pluginDescriptor.setApplicationIcon(packageInfo.applicationInfo.icon);
    pluginDescriptor.setApplicationLogo(packageInfo.applicationInfo.logo);

    // 第3步,检查插件是否已经存在,若存在删除旧的
    PluginDescriptor oldPluginDescriptor =
        getPluginDescriptorByPluginId(pluginDescriptor.getPackageName());
    if (oldPluginDescriptor != null) {
      LogUtil.e("已安装过,先删除旧版本", pluginDescriptor.getInstalledPath());
      remove(pluginDescriptor.getPackageName());
    }

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

    if (!isCopySuccess) {

      LogUtil.d("复制插件到安装目录失败", srcPluginFile);
      new File(srcPluginFile).delete();
      return COPY_FILE_FAIL;
    } else {

      // 第5步,复制插件so到插件so目录, 在构造插件Dexclassloader的时候,会使用这个so目录作为参数
      File tempDir = new File(new File(destPluginFile).getParentFile(), "temp");
      Set<String> soList = FileUtil.unZipSo(srcPluginFile, tempDir);
      if (soList != null) {
        for (String soName : soList) {
          FileUtil.copySo(
              tempDir, soName, new File(destPluginFile).getParent() + File.separator + "lib");
        }
        FileUtil.deleteAll(tempDir);
      }

      // 第6步 添加到已安装插件列表
      pluginDescriptor.setInstalledPath(destPluginFile);
      boolean isInstallSuccess = pluginManager.addOrReplace(pluginDescriptor);

      new File(srcPluginFile).delete();

      if (!isInstallSuccess) {
        LogUtil.d("安装插件失败", srcPluginFile);
        return INSTALL_FAIL;
      } else {
        changeListener.onPluginInstalled(
            pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
        LogUtil.d("安装插件成功", destPluginFile);
        return SUCCESS;
      }
    }
  }
  /**
   * 构造插件信息
   *
   * @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() + "完成");
      }
    }
  }