[Unity] Unity embedded Web Mining record - ULiteWebView

[Unity] Unity embedded Web Mining record - ULiteWebView

preface

The project needs to require Unity project to interact with H5, which is really difficult for me. However, the good thing is that the Kung Fu is not inferior to the intentional people. After constant exploration, they have found a solution. Here I would like to thank the author of the ULiteWebView plug-in, who is very enthusiastic to help me solve some doubts, as well as the friends around me, who have helped me more or less. Add in Download link

first

The official Demo should be easy enough to get started with the usage of ULiteWebView. It should be noted that only LoadHtml can be loaded when it is running on the mobile phone

a key

The reason for ULiteWebView to play video only with sound and no picture is that hardware acceleration is not enabled. Hardware acceleration needs to be added to the activity in the Android minifest file
android:hardwareAccelerated="true" .
Here comes the point! When you try to put a custom Android minifest in Unity, and start hardware acceleration, pack the completed apk
Video cannot be rendered while running on the phone. What's the reason?

First of all, I package the project as an Android project [the external link image transfer failed, and the source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-tewcz2bu-1592554286811) (/ images / ulitewebview/ builtsetting.png )], and view the packaged Minifest file

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="pieces.jing.ulitewebview" 
    android:versionCode="1" android:versionName="1.0" 
    android:installLocation="preferExternal">
  <supports-screens 
    android:smallScreens="true" 
    android:normalScreens="true" 
    android:largeScreens="true" 
    android:xlargeScreens="true" 
    android:anyDensity="true" />
  <application 
    android:theme="@style/UnityThemeSelector"
     android:label="@string/app_name" 
     android:isGame="true" 
     android:banner="@drawable/app_banner" 
     android:icon="@mipmap/app_icon">
    <activity 
        android:label="@string/app_name" 
        android:screenOrientation="sensorLandscape" 
        android:launchMode="singleTask" 
        android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" 
        android:hardwareAccelerated="false" 
        android:name="pieces.jing.ulitewebview.UnityPlayerActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
      </intent-filter>
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
    </activity>
    <meta-data android:name="unity.build-id" android:value="9757b814-10c8-4646-8b69-94d7049a5648" />
    <meta-data android:name="unity.splash-mode" android:value="0" />
    <meta-data android:name="unity.splash-enable" android:value="True" />
  </application>
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
  <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
</manifest>

You can see line 23 android:hardwareAccelerated= “false” . what!? I'm not set to true. Although I don't quite understand Android, I guess my custom Minifest was overwritten when it was packaged and merged. Then what shall I do? After I couldn't find a solution on all kinds of websites in China, I decided to send an investigation team to find out the reason. Sure enough, all the elder brothers outside the wall are talents 233, and soon found a solution.

enclosed link

According to the translation of my site English, I think it's only after my minifest is overwritten that I modify hardwareaccepted and overwrite the already overwritten minifest (FOG). By the way, this method can only be passed through Gradle packaging. Remember to cancel the Export Project option. Of course, when using the Gradle to pack, I think we will encounter a pair of problems, which is 233. I'll give you a rough introduction later.

OK, we will copy the script we need to use and put it in the Unity Editor directory. The code is as follows

using System.Collections;
using System.IO;
using System.Text;
using System.Xml;
using UnityEditor.Android;
using UnityEditor.Callbacks;
//using UnityEditor.iOS.Xcode;
using UnityEditor;
using UnityEngine;

#if UNITY_2018_1_OR_NEWER
public class UnityWebViewPostprocessBuild : IPostGenerateGradleAndroidProject
#else
public class UnityWebViewPostprocessBuild
#endif
{
    //// for android/unity 2018.1 or newer
    //// cf. https://forum.unity.com/threads/android-hardwareaccelerated-is-forced-false-in-all-activities.532786/
    //// cf. https://github.com/Over17/UnityAndroidManifestCallback

    public void OnPostGenerateGradleAndroidProject(string basePath) {
        Debug.Log("adjusted AndroidManifest.xml.");
        var androidManifest = new AndroidManifest(GetManifestPath(basePath));
        androidManifest.SetHardwareAccelerated(true);
        androidManifest.Save();
    }

    public int callbackOrder {
        get {
            return 1;
        }
    }

    private string GetManifestPath(string basePath) {
        var pathBuilder = new StringBuilder(basePath);
        pathBuilder.Append(Path.DirectorySeparatorChar).Append("src");
        pathBuilder.Append(Path.DirectorySeparatorChar).Append("main");
        pathBuilder.Append(Path.DirectorySeparatorChar).Append("AndroidManifest.xml");
        return pathBuilder.ToString();
    }

    //// for others

#if UNITYWEBVIEW_ANDROID_USE_ACTIVITY_NAME
    // please modify ACTIVITY_NAME if you set UNITYWEBVIEW_ANDROID_USE_ACTIVITY_NAME and utilize any custom activty.
    private const string ACTIVITY_NAME = "com.unity3d.player.UnityPlayerActivity";
#endif

    [PostProcessBuild(100)]
    public static void OnPostprocessBuild(BuildTarget buildTarget, string path) {
#if !UNITY_2018_1_OR_NEWER
        if (buildTarget == BuildTarget.Android) {
            string manifest = Path.Combine(Application.dataPath, "Plugins/Android/AndroidManifest.xml");
            if (!File.Exists(manifest)) {
                string manifest0 = Path.Combine(Application.dataPath, "../Temp/StagingArea/AndroidManifest-main.xml");
                if (!File.Exists(manifest0)) {
                    Debug.LogError("cannot find both Assets/Plugins/Android/AndroidManifest.xml and Temp/StagingArea/AndroidManifest-main.xml. please build the app to generate Assets/Plugins/Android/AndroidManifest.xml and then rebuild it again.");
                    return;
                } else {
                    File.Copy(manifest0, manifest);
                }
            }
            XmlDocument doc = new XmlDocument();
            doc.Load(manifest);
            XmlElement activity = SearchActivity(doc);
            if (activity != null
                && string.IsNullOrEmpty(activity.GetAttribute("android:hardwareAccelerated"))) {
                activity.SetAttribute("hardwareAccelerated", "http://schemas.android.com/apk/res/android", "true");
                doc.Save(manifest);
                Debug.LogError("adjusted AndroidManifest.xml about android:hardwareAccelerated. Please rebuild the app.");
            }
#if UNITY_5_6_0 || UNITY_5_6_1
            if (activity != null
                && activity.GetAttribute("android:name") == "com.unity3d.player.UnityPlayerActivity") {
                activity.SetAttribute("name", "http://schemas.android.com/apk/res/android", "net.gree.unitywebview.CUnityPlayerActivity");
                doc.Save(manifest);
                Debug.LogError("adjusted AndroidManifest.xml about android:name. Please rebuild the app.");
            }
#endif
        }
#endif
     /*   if (buildTarget == BuildTarget.iOS) {
            string projPath = path + "/Unity-iPhone.xcodeproj/project.pbxproj";
            PBXProject proj = new PBXProject();
            proj.ReadFromString(File.ReadAllText(projPath));
            string target = proj.TargetGuidByName("Unity-iPhone");
            proj.AddFrameworkToProject(target, "WebKit.framework", false);
            File.WriteAllText(projPath, proj.WriteToString());
        }*/
    }

    private static XmlElement SearchActivity(XmlDocument doc) {
        foreach (XmlNode node0 in doc.DocumentElement.ChildNodes) {
            if (node0.Name == "application") {
                foreach (XmlNode node1 in node0.ChildNodes) {
#if UNITYWEBVIEW_ANDROID_USE_ACTIVITY_NAME
                    if (node1.Name == "activity"
                        && ((XmlElement)node1).GetAttribute("android:name") == ACTIVITY_NAME) {
                        return (XmlElement)node1;
                    }
#else
                    if (node1.Name == "activity") {
                        foreach (XmlNode node2 in node1.ChildNodes) {
                            if (node2.Name == "intent-filter") {
                                bool hasActionMain = false;
                                bool hasCategoryLauncher = false;
                                foreach (XmlNode node3 in node2.ChildNodes) {
                                    if (node3.Name == "action"
                                        && ((XmlElement)node3).GetAttribute("android:name") == "android.intent.action.MAIN") {
                                        hasActionMain = true;
                                    } else if (node3.Name == "category"
                                               && ((XmlElement)node3).GetAttribute("android:name") == "android.intent.category.LAUNCHER") {
                                        hasCategoryLauncher = true;
                                    }
                                }
                                if (hasActionMain && hasCategoryLauncher) {
                                    return (XmlElement)node1;
                                }
                            }
                        }
#endif
                    }
                }
            }
        }
        return null;
    }
}

internal class AndroidXmlDocument : XmlDocument {
    private string m_Path;
    protected XmlNamespaceManager nsMgr;
    public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";

    public AndroidXmlDocument(string path) {
        m_Path = path;
        using (var reader = new XmlTextReader(m_Path)) {
            reader.Read();
            Load(reader);
        }
        nsMgr = new XmlNamespaceManager(NameTable);
        nsMgr.AddNamespace("android", AndroidXmlNamespace);
    }

    public string Save() {
        return SaveAs(m_Path);
    }

    public string SaveAs(string path) {
        using (var writer = new XmlTextWriter(path, new UTF8Encoding(false))) {
            writer.Formatting = Formatting.Indented;
            Save(writer);
        }
        return path;
    }
}

internal class AndroidManifest : AndroidXmlDocument {
    private readonly XmlElement ApplicationElement;

    public AndroidManifest(string path) : base(path) {
        ApplicationElement = SelectSingleNode("/manifest/application") as XmlElement;
        Debug.Log ("ApplicationElement: " + ApplicationElement);
    }

    private XmlAttribute CreateAndroidAttribute(string key, string value) {
        XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace);
        attr.Value = value;
        return attr;
    }

    internal XmlNode GetActivityWithLaunchIntent() {
        return
            SelectSingleNode(
                "/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and "
                + "intent-filter/category/@android:name='android.intent.category.LAUNCHER']",
                nsMgr);
    }

    internal void SetHardwareAccelerated(bool enabled) {
        var activity = GetActivityWithLaunchIntent() as XmlElement;
        activity.SetAttribute("android:hardwareAccelerated", (enabled) ? "true" : "false");
    }
}

ok! Go pack and try!

The pit where Gradle failed to pack

  1. If you see this, you should be crushed by Gradle. Anyway, I've been crazy all day! I'm not sure about the specific problems, but I still know the general direction. First of all, Gradle packaging needs to be connected to the Internet. If you pack the card in the last step for a long time, then it's probably a network problem. You can disconnect the network and try it, and it's estimated that the packaging will fail (highlight: wall climbing tool).
  2. Check the version of gradle used by Unity. The path is Temp/gradleOut/.gradle under the Temp folder of the same level as the project Assets folder. I download version 5.1.1 automatically when packing, as shown in the figure

    Then we open PlayerSetting and check Custom Gradle Template!

    A file will be generated accordingly

    Modify mainTemplate file

    Notice that google() is on jcenter(). Don't ask me why. I don't know. Here, the version of gradle corresponds to the figure above. I use 5.1.1 for Unity, so it should correspond to 3.4.0.

Of course, there are some trivial pits that need to be worked out by ourselves~

|I'm going to go to the hospital, I'm going to go to the hospital, I'm going to go to the hospital Personal blog address

Tags: Android Unity xml Gradle

Posted on Fri, 19 Jun 2020 05:45:31 -0400 by phpusers