How to install Android apk from code in unity

后端 未结 4 1519
终归单人心
终归单人心 2020-11-29 11:43

I found snippet for Java. How can I write such a code in C# Unity?

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_T         


        
4条回答
  •  借酒劲吻你
    2020-11-29 12:30

    You can build a jar/aar plugin and call it from C#. That's more easier to do.

    Another solution is to use AndroidJavaObject and AndroidJavaClass to do this directly without a plugin. Doing it with AndroidJavaObject and AndroidJavaClass requires lots of testing to get it right. Below is what I use to do that. It downloads an APK then installs it.

    First of all create a UI text called "TextDebug" so it you will see what's going on during the download/install. If you don't do this you must comment out or remove all the GameObject.Find("TextDebug").GetComponent().text... line of code.

    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 header = new Dictionary();
        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 = "Stat: " + www.progress;
            yield return null;
        }
    
        byte[] yourBytes = www.bytes;
    
        GameObject.Find("TextDebug").GetComponent().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 = "Created Dir";
        }
    
        try
        {
            //Now Save it
            System.IO.File.WriteAllBytes(savePath, yourBytes);
            Debug.Log("Saved Data to: " + savePath.Replace("/", "\\"));
            GameObject.Find("TextDebug").GetComponent().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 = "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("ACTION_VIEW");
            int FLAG_ACTIVITY_NEW_TASK = intentObj.GetStatic("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("fromFile", fileObj);
    
            intent.Call("setDataAndType", uri, "application/vnd.android.package-archive");
            intent.Call("addFlags", FLAG_ACTIVITY_NEW_TASK);
            intent.Call("setClassName", "com.android.packageinstaller", "com.android.packageinstaller.PackageInstallerActivity");
    
            AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject currentActivity = unityPlayer.GetStatic("currentActivity");
            currentActivity.Call("startActivity", intent);
    
            GameObject.Find("TextDebug").GetComponent().text = "Success";
            return true;
        }
        catch (System.Exception e)
        {
            GameObject.Find("TextDebug").GetComponent().text = "Error: " + e.Message;
            return false;
        }
    }
    

    For Android API 24 and above, this requires a different code since the API changed. The C# code below is based on the this Java answer.

    //For API 24 and above
    private bool installApp(string apkPath)
    {
        bool success = true;
        GameObject.Find("TextDebug").GetComponent().text = "Installing App";
    
        try
        {
            //Get Activity then Context
            AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject currentActivity = unityPlayer.GetStatic("currentActivity");
            AndroidJavaObject unityContext = currentActivity.Call("getApplicationContext");
    
            //Get the package Name
            string packageName = unityContext.Call("getPackageName");
            string authority = packageName + ".fileprovider";
    
            AndroidJavaClass intentObj = new AndroidJavaClass("android.content.Intent");
            string ACTION_VIEW = intentObj.GetStatic("ACTION_VIEW");
            AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);
    
    
            int FLAG_ACTIVITY_NEW_TASK = intentObj.GetStatic("FLAG_ACTIVITY_NEW_TASK");
            int FLAG_GRANT_READ_URI_PERMISSION = intentObj.GetStatic("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("getUriForFile", unityContext, authority, fileObj);
    
            intent.Call("setDataAndType", uri, "application/vnd.android.package-archive");
            intent.Call("addFlags", FLAG_ACTIVITY_NEW_TASK);
            intent.Call("addFlags", FLAG_GRANT_READ_URI_PERMISSION);
            currentActivity.Call("startActivity", intent);
    
            GameObject.Find("TextDebug").GetComponent().text = "Success";
        }
        catch (System.Exception e)
        {
            GameObject.Find("TextDebug").GetComponent().text = "Error: " + e.Message;
            success = false;
        }
    
        return success;
    }
    

    EDIT:

    If you get the Exception:

    Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.packageItemInfo.loadXmlMetaData(android.c‌​ontent.pm.PackageMan‌​ager.java.lang.Strin‌​g)'

    You have to do few things.

    1.Copy "android-support-v4.jar" from your "AndroidSDK/extras/android/support/v4/android-support-v4.jar" directory to your "UnityProject/Assets/Plugins/Android" directory.

    2.Create a file called "AndroidManifest.xml" in your UnityProject/Assets/Plugins/Android directory and put the code below into it.

    Make sure to replace "com.company.product" with your own package name. There are 2 instances where this appeared. You must replace both of them:

    These are found in package="com.company.product" and android:authorities="com.company.product.fileprovider". Don't change or remove the "fileprovider" and don't change anything else.

    Here is the "AndroidManifest.xml" file:

    
    
      
      
        
          
            
            
          
          
        
    
        
          
        
    
      
      
    
    

    3.Create a new file called "provider_paths.xml" in your "UnityProject/Assets/Plugins/Android/res/xml" directory and put the code below in it. As you can see, you have to create a res and then an xml folder.

    Make sure to replace "com.company.product" with your own package name. It only appeared once.

    Here is what you should put into this "provider_paths.xml" file:

    
    
      
      
      
    
    

提交回复
热议问题