当前位置: 首页 > 知识库问答 >
问题:

如何从unity中的代码安装Android apk

诸正谊
2023-03-14

我找到了Java的代码片段。我如何用C#Unity编写这样的代码?

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);

共有3个答案

解河
2023-03-14
匿名用户

随着Unity的更新版本,它变得更加复杂Assets/Plugins/Android/res被弃用。还有Android 9.0Android。支持v4被合并到androidx中。核心所有东西都被重新命名和移动。幸运的是,Unity现在在支持Android插件方面做得更好了一些,因此使用这个解决方案,您不再需要向项目中添加任何jar或aar。

请注意,Android有一堆与此安装过程相关的唠叨屏幕。每个应用程序都有一个一次性接受不受信任的版本的屏幕,如果您在设备上使用了google play,play protected会添加一堆屏幕,使您的应用程序看起来像恶意软件。(这是一件好事,因为您应该只在您拥有的信息亭模式风格的设备上执行这些操作,您可以在其中关闭Play Protect。)

增加了程序员的答案。在Unity 2019和2020中,您可以直接在Unity中编译插件,而不再需要jar文件。2019年,它需要在Assets/Plugins/Android中,并有几个额外的文件。2020年,文件夹只需要后缀。androidlib可以位于资产中的任何位置。

package.androidlib
  src
    main
      res
        xml
          provider_paths.xml
      AndroidManifest.xml
  build.gradle
  AndroidManifest.xml  (only for 2019)
  project.properties  (only for 2019)

提供者路径。xml:正如程序员所解释的。

AndroidManifest.xml:主要是为了给这个新库一个bundle ID。这不应该匹配任何其他ID;它可以是任何东西,通常是com.companyname.packagename。请注意,它在main/文件夹内

我们也可以在这里做其余的AndroidManifest.xml的东西,因为现在所有的AndroidManifest.xml文件都将在最终的APK中得到合并。FileProvider包已更改为androidx.core.content.FileProvider

我注意到你需要Android系统。准许请求安装软件包;但我不确定您是否需要像Kaushix建议的那样读取外部存储/写入外部存储。(可能在某些设备上?我认为这是项目设置所涵盖的。)-

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.anything.anythingelse">
    <application>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            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" />
</manifest>

建筑gradle:这应该与你的项目目标和min SDK版本相匹配。如果更少也没关系,但target至少需要28岁才能使用androidx。

apply plugin: 'com.android.library'

android {
    compileSdkVersion 28


    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 28
    }
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.1.0'
}

对于2019年,额外的AndroidManifest.xml和project.properties文件纯粹是为了告诉Unity构建这个文件夹而存在的。在2020年,Unity的聪明到不需要它们。

AndroidManifest。xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- This extra manifest, as well as project.properties in this folder shouldn't be necessary with the newer gradle project format. Can remove if you upgrade to 2020.1. -->
</manifest>

project.properties:

android.library=true

AndroidPostProcess。反恐精英:

我们还需要一个编辑器脚本来在主gradle文件中启用AndroidX支持,并打开Jetifier,它应该修复针对旧android.support库编译的任何其他插件。

using UnityEditor.Android;

public class AndroidPostProcess : IPostGenerateGradleAndroidProject
{
    public int callbackOrder => 0;
    public void OnPostGenerateGradleAndroidProject(string path)
    {
        string gradlePropertiesPath = path + "/gradle.properties";
        string[] lines = File.ReadAllLines(gradlePropertiesPath);

        StringBuilder builder = new StringBuilder();
        foreach (string line in lines)
        {
            if (line.Contains("android.useAndroidX"))
            {
                continue;
            }
            if (line.Contains("android.enableJetifier"))
            {
                continue;
            }
            builder.AppendLine(line);
        }
        builder.AppendLine("android.useAndroidX=true");
        builder.AppendLine("android.enableJetifier=true");
        File.WriteAllText(gradlePropertiesPath, builder.ToString());
    }
}

杨超
2023-03-14

我只是想在@程序员给出的梦幻般的答案中添加一个更新,以反映AndroidSDK和Unity的变化。我希望它能对其他人有用。我正在使用SDK版本26和Unity 2017.3.1。我对几乎所有这些都是新的,所以如果我错过或误解了什么,请纠正我!

>

<?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

虽然在构建过程中Unity给出了过时的警告——如果不推荐使用Assets/Plugins/Android/res中的Android资源,请将您的资源转移到AAR或Android库中。。要解决这个问题,请创建一个新的zip文件并放置您的AndroidManifest。xml位于zip的顶层。然后添加提供者路径。@Programmer将详细的xml放入文件夹结构res/xml/provider_path中的zip中。xml。重新命名拉链,使其更美观。aar文件扩展名,然后将其拖到Unity project Assets/Plugins文件夹中。我更改AndroidManifest的原因。com的xml条目。公司productsomethingelse是我使用com的时候。公司产品统一构建过程引发了命名冲突。我认为,因为清单现在在一个单独的aar中,所以它需要有一个不同的包名。

宋奇希
2023-03-14

您可以构建一个jar/aar插件,并从C#调用它。这更容易做到。

另一种解决方案是使用AndroidJavaObjectAndroidJavaClass直接执行此操作,而无需插件。使用AndroidJavaObjectAndroidJavaClass执行此操作需要大量测试才能正确执行。下面是我用来执行此操作的。它下载一个APK然后安装它。

首先创建一个名为"TextDebug"的UI文本,以便在下载/安装过程中看到发生了什么。如果你不这样做,你必须注释掉或删除所有GameObject。查找("TextDebug")。GetComponent

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.XmlResourceParserandroid.content.pm.packageItemInfo.loadXmlMetaData(android. content.pm.PackageManager.java.lang.Strin g)'

你几乎不需要做什么。

1.将"android-support-v4.jar"从您的"AndroidSDK/附加功能/android/support/v4/android-support-v4.jar"目录复制到您的"UnityProject/资产/插件/Android"目录。

2.在UnityProject/Assets/Plugins/Android目录中创建一个名为“AndroidManifest.xml”的文件,并将下面的代码放入其中。

确保用自己的软件包名称替换“com.company.product”。有两个例子出现了这种情况。必须同时更换这两个部件:

这些可以在package=“com.company.product”和android:authorities=“com.company.product.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.在“UnityProject/Assets/Plugins/Android/res/xml”目录中创建一个名为“provider_paths.xml”的新文件,并将下面的代码放入其中。如您所见,您必须创建一个res,然后创建一个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>

 类似资料:
  • 首先你需要安装Golang,关于Golang的安装,参见官方文档 install instructions。 下载 你需要获取Gitea的源码,最方便的方式是使用 go 命令。执行以下命令: go get -d -u code.gitea.io/gitea cd $GOPATH/src/code.gitea.io/gitea 然后你可以选择编译和安装的版本,当前你有多个选择。如果你想编译 mas

  • 使用指南 - 代码安装 - 安装方法 - 如何手动安装代码 只有在正确地添加了百度统计代码后,才能获取尽可能准确的流量数据,代码安装过程中需要注意以下几点: 代码的安装位置要正确,请将异步分析代码安装在标签</head>标记前。 一个页面中不要重复安装相同的代码,统计有去重规则,一般不会重复计算。一段代码生效后,另外一段代码就会废弃,但建议只安装一段代码。 不要对代码有任何编辑操作,随意编辑代码会

  • 使用指南 - 代码安装 - 安装方法 - 如何自动安装代码 如果您是直接向空间提供商购买的网站,请向该空间提供商询问您网站的FTP用户名和密码。 如果您是委托建站公司为您建立的网站,请提前询问建站公司,网站的FTP用户名和密码,一般该类公司在建站完成后,都会以邮件形式向您发送网站FTP用户名和密码,请您仔细查询以获得您网站的FTP用户名和密码。 如果您网站有专门人员进行管理,请向他们询问,以获得网

  • 我正在尝试从源代码处安装Rundeck。我尝试了Linux的三种不同发行版(Debian、Red Hat和SUSE发行版)。所有人都有失败的经历。在继续之前,我安装make命令、Java和Git。“make”命令在我尝试过的每一个Linux发行版上都是失败的。“./gradlew build”命令也没有成功。 配置项目:生成版本3.2.7-快照 任务:rundeckapp:grails-spa:r

  • 我是全栈开发者(PHP JS)。 我想要一个后端VS代码和一个前端VS代码。 我在教程中看到了一个绿色的VS代码,但我不知道如何将两个VS代码安装在一起。

  • 本书面向的是已经对Go语言有一定的经验,希望能了解它的底层机制的用户。因此,只推荐从源代码安装Go。 Go源码安装 在Go的源代码中,有些部分是用Plan 9 C和AT&T汇编写的,因此假如你要想从源码安装,就必须安装C的编译工具。 在Mac系统中,只要你安装了Xcode,就已经包含了相应的编译工具。 在类Unix系统中,需要安装gcc等工具。例如Ubuntu系统可通过在终端中执行sudo apt