如何从统一代码安装Android APK如何从统一代码安装Android APK(How to in

2019-05-12 06:58发布

我发现片段为Java。 我怎么能写C#统一这样的代码?

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.fromFile(new File("link to downloaded file")),"application/vnd.android.package-archive");
startActivity(intent);

Answer 1:

你可以建立一个JAR / AAR插件,并从C#调用它。 这是更容易做到。

另一种解决方案是使用AndroidJavaObjectAndroidJavaClass做到这一点的情况下直接的插件。 用做AndroidJavaObjectAndroidJavaClass需要大量的测试,以得到它的权利。 下面是我用它来做到这一点。 它下载的APK然后安装它。

首先,创建一个名为“TextDebug”所以,你会看到在下载过程中发生了什么事情的UI文本/安装。 如果你不这么做,你必须注释掉或删除所有GameObject.Find("TextDebug").GetComponent<Text>().text...代码行。

void Start()
{
    StartCoroutine(downLoadFromServer());
}

IEnumerator downLoadFromServer()
{
    string url = "http://apkdl.androidapp.baidu.com/public/uploads/store_2/f/f/a/ffaca37aaaa481003d74725273c98122.apk?xcode=854e44a4b7e568a02e713d7b0af430a9136d9c32afca4339&filename=unity-remote-4.apk";


    string savePath = Path.Combine(Application.persistentDataPath, "data");
    savePath = Path.Combine(savePath, "AntiOvr.apk");

    Dictionary<string, string> header = new Dictionary<string, string>();
    string userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36";
    header.Add("User-Agent", userAgent);
    WWW www = new WWW(url, null, header);


    while (!www.isDone)
    {
        //Must yield below/wait for a frame
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Stat: " + www.progress;
        yield return null;
    }

    byte[] yourBytes = www.bytes;

    GameObject.Find("TextDebug").GetComponent<Text>().text = "Done downloading. Size: " + yourBytes.Length;


    //Create Directory if it does not exist
    if (!Directory.Exists(Path.GetDirectoryName(savePath)))
    {
        Directory.CreateDirectory(Path.GetDirectoryName(savePath));
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Created Dir";
    }

    try
    {
        //Now Save it
        System.IO.File.WriteAllBytes(savePath, yourBytes);
        Debug.Log("Saved Data to: " + savePath.Replace("/", "\\"));
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Saved Data";
    }
    catch (Exception e)
    {
        Debug.LogWarning("Failed To Save Data to: " + savePath.Replace("/", "\\"));
        Debug.LogWarning("Error: " + e.Message);
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Error Saving Data";
    }

    //Install APK
    installApp(savePath);
}

public bool installApp(string apkPath)
{
    try
    {
        AndroidJavaClass intentObj = new AndroidJavaClass("android.content.Intent");
        string ACTION_VIEW = intentObj.GetStatic<string>("ACTION_VIEW");
        int FLAG_ACTIVITY_NEW_TASK = intentObj.GetStatic<int>("FLAG_ACTIVITY_NEW_TASK");
        AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);

        AndroidJavaObject fileObj = new AndroidJavaObject("java.io.File", apkPath);
        AndroidJavaClass uriObj = new AndroidJavaClass("android.net.Uri");
        AndroidJavaObject uri = uriObj.CallStatic<AndroidJavaObject>("fromFile", fileObj);

        intent.Call<AndroidJavaObject>("setDataAndType", uri, "application/vnd.android.package-archive");
        intent.Call<AndroidJavaObject>("addFlags", FLAG_ACTIVITY_NEW_TASK);
        intent.Call<AndroidJavaObject>("setClassName", "com.android.packageinstaller", "com.android.packageinstaller.PackageInstallerActivity");

        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        currentActivity.Call("startActivity", intent);

        GameObject.Find("TextDebug").GetComponent<Text>().text = "Success";
        return true;
    }
    catch (System.Exception e)
    {
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Error: " + e.Message;
        return false;
    }
}

Android API 24以上,这需要不同的代码,因为API改变。 下面的C#代码是基于这个 Java的答案。

//For API 24 and above
private bool installApp(string apkPath)
{
    bool success = true;
    GameObject.Find("TextDebug").GetComponent<Text>().text = "Installing App";

    try
    {
        //Get Activity then Context
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaObject unityContext = currentActivity.Call<AndroidJavaObject>("getApplicationContext");

        //Get the package Name
        string packageName = unityContext.Call<string>("getPackageName");
        string authority = packageName + ".fileprovider";

        AndroidJavaClass intentObj = new AndroidJavaClass("android.content.Intent");
        string ACTION_VIEW = intentObj.GetStatic<string>("ACTION_VIEW");
        AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);


        int FLAG_ACTIVITY_NEW_TASK = intentObj.GetStatic<int>("FLAG_ACTIVITY_NEW_TASK");
        int FLAG_GRANT_READ_URI_PERMISSION = intentObj.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION");

        //File fileObj = new File(String pathname);
        AndroidJavaObject fileObj = new AndroidJavaObject("java.io.File", apkPath);
        //FileProvider object that will be used to call it static function
        AndroidJavaClass fileProvider = new AndroidJavaClass("android.support.v4.content.FileProvider");
        //getUriForFile(Context context, String authority, File file)
        AndroidJavaObject uri = fileProvider.CallStatic<AndroidJavaObject>("getUriForFile", unityContext, authority, fileObj);

        intent.Call<AndroidJavaObject>("setDataAndType", uri, "application/vnd.android.package-archive");
        intent.Call<AndroidJavaObject>("addFlags", FLAG_ACTIVITY_NEW_TASK);
        intent.Call<AndroidJavaObject>("addFlags", FLAG_GRANT_READ_URI_PERMISSION);
        currentActivity.Call("startActivity", intent);

        GameObject.Find("TextDebug").GetComponent<Text>().text = "Success";
    }
    catch (System.Exception e)
    {
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Error: " + e.Message;
        success = false;
    }

    return success;
}

编辑:

如果你得到了异常:

试图调用虚拟方法 'android.content.res.XmlResourceParser android.content.pm.packageItemInfo.loadXmlMetaData(android.c ontent.pm.PackageMan ager.java.lang.Strin克)'

你必须做一些事情。

1 .Copy “Android的支持,v4.jar”从“AndroidSDK /演员/安卓/支持/ V4 / Android的支持,v4.jar”目录到你的“UnityProject /资产/插件/ Android”的目录。

2 .Create一个在你的UnityProject /资产/插件/ Android的目录名为“AndroidManifest.xml中”文件,并把下面的代码进去。

确保用自己的包名称来代替“com.company.product”。2个实例,其中该出现了。 您必须替换他们两个:

这些在包装=“com.company.product”android发现:当局=“com.company.product.fileprovider”。 不要更改或删除“fileprovider”并不会改变任何东西。

这里是“的AndroidManifest.xml”文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product" xmlns:tools="http://schemas.android.com/tools" android:installLocation="preferExternal" android:versionName="1.0" android:versionCode="1">
  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
  <application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true">
    <activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
    </activity>

    <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="com.company.product.fileprovider"
          android:exported="false"
          android:grantUriPermissions="true">
      <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths"/>
    </provider>

  </application>
  <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
</manifest>

3 .Create一个在你的“UnityProject /资产/插件/ Android设备/ RES / XML”目录下名为“provider_paths.xml”的新文件,并把下面的代码在里面。 正如你所看到的,你必须创建一个水库 ,然后一个XML文件夹。

确保用自己的包名称来代替“com.company.product”。 它仅出现过一次

下面是你应该把什么这个“provider_paths.xml”文件:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <!--<external-path name="external_files" path="."/>-->
  <external-path path="Android/data/com.company.product" name="files_root" />
  <external-path path="." name="external_storage_root" />
</paths>


Answer 2:

我只是想更新添加到由@Programmer给出的答案梦幻,以反映更改Android SDK和统一。 我希望它可以给别人有用。 我与SDK版本26和Unity 2017年3月1日的工作。 我是新来的,几乎所有的这所以请不要纠正我,如果我错过或误解的东西!

  1. Android的支持 - v4.jar(用于获取FileProvider类)不再可用。 对于版本到24.1.1它位于的Android \ SDK \演员\机器人\ m2repository \ COM \机器人\ SUPPORT \支持-V4 \ 24.1.1但版本后,你必须而不是在Android上使用支持核-utils的\ SDK \演员\机器人\ m2repository \ COM \机器人\ SUPPORT \支持核心-utils的 。 相反,一个jar文件的使用相关的.aar文件拖动到您的统一项目Plugins文件夹。
  2. 您需要android.permission.REQUEST_INSTALL_PACKAGES添加到您的AndroidManifest.xml

     <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.productsomethingelse" xmlns:tools="http://schemas.android.com/tools" android:installLocation="preferExternal" android:versionName="1.0" android:versionCode="1"> <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" /> <application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true"> <activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> </activity> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.company.product.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider> </application> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="26" /> </manifest> 

    请注意,我也改变com.company.product的一审com.company.productsomethingelse

  3. 现在应该建立正常工作,但在生成过程中团结是给予警告已淘汰-提供的资产/插件的Android资源/安卓/ RES已过时,请移动你的资源的AAR或Android库。 。 为了避开这个创建一个新的压缩文件,并把你的AndroidManifest.xml在拉链的顶层。 然后添加由@Programmer详述到的文件夹结构RES / XML / provider_paths.xml拉链的provider_paths.xml。 重命名拉链给它一个.aar文件扩展名,然后将其拖动到您的统一项目资产/ Plugins文件夹。 我改变了AndroidManifest.xml中进入com.company.productsomethingelse的原因是,当我用com.company.product统一建设过程中被扔了一个命名冲突。 我想是因为清单,现在是在一个单独的AAR它需要有一个独特的包名。



文章来源: How to install Android apk from code in unity