在Unity中获取Android安装的应用程序图标
问题描述:
我正在写一个相当困难的(对我来说)问题。 快速地,我想要获取设备中的所有已安装的应用程序(图标和标签)。我正在使用一个简单的代码来获取应用程序的名称。我使用Android Java Class来获取这些信息。问题在于Android将应用程序图标视为“可绘制”。 Unity无法读取并显示为Sprite。我想知道是否有办法解决这个问题。我试图将drawable编码为base64字符串,但Unity以“无效字符串长度”错误回复我,可能是base64字符串的“无限”长度。我试图将Drawable转换为一个字节数组,然后使用它创建一个Texture.loadImage(byte [])的纹理,但它不起作用。 下面是代码:在Unity中获取Android安装的应用程序图标
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = jc.GetStatic<AndroidJavaObject>("currentActivity");
int flag = new AndroidJavaClass("android.content.pm.PackageManager").GetStatic<int>("GET_META_DATA");
AndroidJavaObject pm = currentActivity.Call<AndroidJavaObject>("getPackageManager");
AndroidJavaObject packages = pm.Call<AndroidJavaObject>("getInstalledApplications", flag);
int count = packages.Call<int>("size");
string[] names = new string[count];
int ii =0;
for(int i=0; ii<count;){
//get the object
AndroidJavaObject currentObject = packages.Call<AndroidJavaObject>("get", ii);
try{
//try to add the variables to the next entry
names[i] = pm.Call<string>("getApplicationLabel", currentObject);
AndroidJavaObject icon = pm.Call<AndroidJavaObject>("getApplicationIcon", currentObject);//this part is the Java (Android Studio) code using Android Java Object and Class of Unity. Maybe the error is from here
AndroidJavaObject bitmap = icon.Call<AndroidJavaObject>("getBitmap");
AndroidJavaClass stream = new AndroidJavaClass("java.io.ByteArrayOutputStream");
bitmap.Call("compress",(new AndroidJavaClass("java.io.ByteArrayOutputStream")).Call<AndroidJavaObject>("JPEG"), 100, stream);
byte[] bitMapData = stream.Call<byte[]>("toByteArray");//to here
Texture2D mytexture = new Texture2D(50, 50); // no idea what default size would be?? is it important??
if (!mytexture.LoadImage(bitMapData)) {
Debug.Log("Failed loading image data!");
}
else {
Debug.Log("LoadImage - Still sane here - size: " + mytexture.width + "x" + mytexture.height);
GameObject app = (GameObject)Instantiate(App, Vector3.zero, Quaternion.identity);
app.GetComponent<RawImage>().texture = mytexture;//here is the code should display the icon as texture (sprite would be the best)
}
i++;
ii++;
}
catch(Exception e){
Debug.LogError(e,this);
//if it fails, just go to the next app and try to add to that same entry.
ii++;
}
}
这里就有了Java的Android工作室工作代码:
Bitmap bitmap = ((BitmapDrawable) item.getIcon()).getBitmap(); //item.getIcon() returns the Drawable correctly
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] byteArray = baos.toByteArray();
感谢您的帮助。
答
我在Android Studio(无活动)上创建了一个Android Jar插件,然后将其导入Unity3D(AndroidManifest.xml和classes.jar,位于Assets> Plugins> Android> libs中)。在插件内部,我添加了一个类,然后添加了void来获取图标的字节[]。 Java的Android的插件类:
public class PluginClass {
public static byte[] getIcon(PackageManager pm, ApplicationInfo applicationInfo) {
try {
BitmapDrawable icon = (BitmapDrawable) pm.getApplicationIcon(applicationInfo);
Bitmap bmp = icon.getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
return byteArray;
} catch (Exception e) {
return null;
}
}
public static boolean isSystem(ApplicationInfo applicationInfo){
return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
}
Then I have invoked it in Unity C# script:
void Start() {
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = jc.GetStatic<AndroidJavaObject>("currentActivity");
int flag = new AndroidJavaClass("android.content.pm.PackageManager").GetStatic<int>("GET_META_DATA");
AndroidJavaObject pm = currentActivity.Call<AndroidJavaObject>("getPackageManager");
AndroidJavaObject packages = pm.Call<AndroidJavaObject>("getInstalledApplications", 0);
int count = packages.Call<int>("size");
string[] names = new string[count];
List<byte[]> byteimg = new List<byte[]>();
int ii =0;
for(int i=0; ii<count;){
AndroidJavaObject currentObject = packages.Call<AndroidJavaObject>("get", ii);
try{
names[i] = pm.Call<string>("getApplicationLabel", currentObject);
var plugin = new AndroidJavaClass("com.mypackagename.PluginClass");
if(plugin.CallStatic<bool>("isSystem",currentObject)){
ii++;
continue;
}
byte[] decodedBytes = plugin.CallStatic<byte[]>("getIcon", pm, currentObject);
Texture2D text = new Texture2D(1, 1, TextureFormat.ARGB32, false);
text.LoadImage(decodedBytes);
Sprite sprite = Sprite.Create (text, new Rect(0,0,text.width,text.height), new Vector2(.5f,.5f));
i++;
ii++;
}
catch(Exception e){
Debug.LogError(e,this);
ii++;
}
}
感谢您的帮助
我不这样做Android开发的,但不能你得到的位图,得到位图的像素,并使用这些像素创建纹理统一?为什么要经历这个缓冲区转换? – bpgeck
原因是没有办法使用Unity,我必须使用Android Java Class来获取位图,并且我不知道如何从Unity中正确调用Java代码。 –
我假设你的意思是Unity本身并不具备与上述Java功能等效的功能。在这种情况下,您可以使用Java编写代码来获取原始颜色值并使用[AndroidJavaObject.Call](https://docs.unity3d.com/ScriptReference/AndroidJavaObject.Call.html)调用该函数。 – bpgeck