Unity(十三) 研究Unity获取Android手机电量、WIFI心得《之二》

----------------------------------------------2021-1-7更新整理完整工程------------------------------------------------------------------

工程下载:https://download.csdn.net/download/LinZhonglong/14040361  AndoridStudio工程

                  https://download.csdn.net/download/LinZhonglong/14040316  Unity2018.4.0工程

----------------------------------------------------------------------------------------------------------------------------------------------

 

本文主要完成两个功能,附上完整流程代码,以便后续查看

使用Unity5.6.3    JavaEclipse(Androidsdk同级目录)

ps:已测2017.3通过,需要增加定位权限

 

功能一:Unity应用实现开机自启动 获取电量WIFI等

1:创建项目 File--Android Application Project

2:导入class.jar     BuildPath-->Add External Archieves-->class.jar(使用Unity5.6.3测试)

D:\Program Files\Unity5.6.3\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes 

注意工程上方的Package Explorer!选错了就不会有Add External Archieves选项

增加WIFI权限(也可以在Unity里手动增加)

3:代码模块

MainActivity.java

package com.example.getinfo;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import com.unity3d.player.UnityPlayerActivity;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;


public class MainActivity extends UnityPlayerActivity {

	private static Context instance;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        instance = getApplication();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    //获取手机当前电量、总电量(默认其实都是100)、当前状态(充电还是放电)
    //其余数据例如电压、电池温度用的较少
    public String MonitorBatteryState()
    {
        IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent intent = instance.registerReceiver(null, iFilter);
        int rawLevel = intent.getIntExtra("level", 0);      //获得当前电量
        int scale = intent.getIntExtra("scale", 0);         //获得总电量
        int status = intent.getIntExtra("status", 0);       //电池充电状态
        int health = intent.getIntExtra("voltage", 0);      //电池健康状况
        int batteryV = intent.getIntExtra("voltage", 0);    //电池电压(mv)
        int temperature = intent.getIntExtra("temperature", 0); //电池温度(数值)
        double t = temperature / 10.0;  //电池摄氏温度,默认获取的非摄氏温度值,需做一下运算转换
        String targetStr = "";
        int level = -1;
        if(rawLevel > 0 && scale > 0)
        {
            level = (rawLevel * 100) / scale;
            targetStr = level + "|" + scale + "|" + status;
        }
        return targetStr;
    }

    //获取Wifi信号强度
    @SuppressWarnings("deprecation")
    private String ObtainWifiInfo()
    {
        String result = "";
        WifiManager wifiManager = (WifiManager)getApplication().getSystemService(WIFI_SERVICE);
        WifiInfo info = wifiManager.getConnectionInfo();
        if(info.getBSSID() != null)
        {
            //链接信号强度
            int strength = WifiManager.calculateSignalLevel(info.getRssi(), 5);
            //链接速度
            int speed = info.getLinkSpeed();
            //链接速度单位
            String units = WifiInfo.LINK_SPEED_UNITS;
            //Wifi源名称
            String ssid = info.getSSID();
            int ip = info.getIpAddress();
            String mac = info.getMacAddress();
            result = strength + "|" + IntToIp(ip) + "|" + mac + "|" + ssid;
        }
        return result;
    }

    private String IntToIp(int paramInt)
    {
        return (paramInt & 0xFF) + "." + (0xFF & paramInt >> 8) + "." + (0xFF & paramInt >> 16) + "." + (0xFF & paramInt >> 24);
    }
}

AndroidMainfest.xml文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.getinfo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="25" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

只是获取电量WIFI以上就行!

 

(拓展)开机自启动   新建一个class

 BootBroadcastReceiver.java  

package com.example.getinfo;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.unity3d.player.UnityPlayerNativeActivity;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;


public class BootBroadcastReceiver extends BroadcastReceiver {
	private final String ACTION_BOOT = "android.intent.action.BOOT_COMPLETED";
	@Override
	public void onReceive(Context context, Intent intent) {
		
		if(intent.getAction().equals(ACTION_BOOT)){
	        Intent myIntent = new Intent(context,MainActivity.class);
	        myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	        context.startActivity(myIntent);
	    }			
	}

}

加入AndroidMainfest文件中(一定要添加开机自启权限和reciever)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.getinfo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="26" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>


    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
       <receiver  android:name=".BootBroadcastReceiver" >   
          <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />       
          </intent-filter>      
       </receiver>
    </application>

</manifest>

 

4:导出jar

5:导入Unity里

6:新建脚本Test.cs   

新建场景后创建一个button 两个text,最好多一个button为了退出应用

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Test : MonoBehaviour 
{
    public Button button;
    public Text phonePowerText;
    public Text wifiText;

    private string batteryData;
    private string wifiData;

    void Awake()
    {
        button.onClick.AddListener(OnButtonClicked);
    }

    private void OnButtonClicked()
    {
        AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
        batteryData = jo.Call<string>("MonitorBatteryState");
        wifiData = jo.Call<string>("ObtainWifiInfo");
        OnBatteryDataBack(batteryData);
        OnWifiDataBack(wifiData);
    }

    //安卓那边将数据以“|”进行分割,所以这边以"|"来分割数据
    private void OnBatteryDataBack(string data)
    {
        phonePowerText.text = "";
        string[] args = data.Split('|');
        if (args[2] == "2")
        {
            phonePowerText.text += "电池充电中\n";
        }
        else
        {
            phonePowerText.text += "电池放电中\n";
        }
        int curPower = int.Parse(args[0]);
        float power = float.Parse(args[1]);
        float percent = curPower / power;
        phonePowerText.text += " cur power:" + curPower;
        phonePowerText.text += "  all power:" + power;
        phonePowerText.text += " 电量比例:" + (Mathf.CeilToInt(percent * 100) + "%").ToString();
    }

    private void OnWifiDataBack(string data)
    {
        wifiText.text = "";
        wifiText.text += wifiData;
        string[] args = wifiData.Split('|');
        int wifiLevel = int.Parse(args[0]);
        wifiText.text += "Wifi信号格数:" + wifiLevel.ToString() + "\n";
        string ip = "IP:" + args[1] + "\n";
        string mac = "MAC:" + args[2] + "\n";
        string ssid = "Wifi Name:" + args[3] + "\n";
        wifiText.text += ip;
        wifiText.text += mac;
        wifiText.text += ssid;
    }
}

6:打包  Pakage Name需要和Eclipse里的包名一致!!!

到这里恭喜你,打包成功!!!

可能出现的问题如下

1:获取不到WIFI名字,显示unknown ssid

解决办法

a: 把Unity里Android目录下的AndroidMainfest文件修改了一下target API=25就行了,因为我Unity的Minimum API Level是16-25(红圈下方),和使用SDK Manager下载的API有关

b:还不行的话就增加定位权限,如下

2:以上测试通过了,换了个Unity版本,例如Unity2017.3  又出现unkown ssid 。通过修改API还是不行

解决办法:把Unity里Android目录下的AndroidMainfest文件增加一个 定位权限,就可以了

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

 

<结束>想了一下还是不附带工程了,毕竟每个人PC上安装Unity的路径不一样,class.jar 。有问题可以留言

 <总结>可以同时导入多个class.jar ,一个WIFI权限基本足够

 

功能二:已有第三方SDK作为MainActivity,如何调取我们的Activity

PS:在游戏开发中我们参考如上已能实现功能,因为UnityPlayerActivity作为2D平面展示应用已经足够,比如手机上或平板上。但如果在VR开发中我们可能就没这个MainActivity了,它可能已经被占用。例如一体机PicoVR。这个时候主窗口是不能切换的,也就是说Actiivity不能切换,直接写一个不继承的java类你会发现报错很多,关键是在Unity里调用不到。我们通过Unity官方提供的AndoridJavaClass这个接口,可以调取currentActivity里的静态/非静态函数。但是在一个没有运行起来的Activity则无法调取非静态函数。

因此我们需要一个静态类或静态函数以供在任何需要的时候调用。

PS:上一个功能里的有些函数在static的驱动下要作出修改,如下

流程如下:

1:删除MainActivity,增加一个供调用的ThirdActivity.java类

package com.example.getinfo;

import com.unity3d.player.UnityPlayer;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.app.Service;

public class ThirdActivity   {		
	//获取电量
	public static String MonitorBatteryState()
        {
        IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent intent = UnityPlayer.currentActivity.getApplicationContext().registerReceiver(null, iFilter);
        int rawLevel = intent.getIntExtra("level", 0);      //获得当前电量
        int scale = intent.getIntExtra("scale", 0);         //获得总电量
        int status = intent.getIntExtra("status", 0);       //电池充电状态
        int health = intent.getIntExtra("voltage", 0);      //电池健康状况
        int batteryV = intent.getIntExtra("voltage", 0);    //电池电压(mv)
        int temperature = intent.getIntExtra("temperature", 0); //电池温度(数值)
        double t = temperature / 10.0;  //
        String targetStr = "";
        int level = -1;
        if(rawLevel > 0 && scale > 0)
        {
            level = (rawLevel * 100) / scale;
            targetStr = level + "|" + scale + "|" + status;
        }
        return targetStr;
    }
	
     //获取WIFI
	 public static String ObtainWifiInfo()
	    {
	        String result = "null";
	        WifiManager wifiManager = (WifiManager)(UnityPlayer.currentActivity.getApplicationContext()).getSystemService(Context.WIFI_SERVICE);
	        WifiInfo info = wifiManager.getConnectionInfo();
	        if(info.getBSSID() != null)
	        {
	            //链接信号强度
	            int strength = WifiManager.calculateSignalLevel(info.getRssi(), 5);
	            //链接速度
	            int speed = info.getLinkSpeed();
	            //链接速度单位
	            String units = WifiInfo.LINK_SPEED_UNITS;
	            //Wifi源名称
	            String ssid = info.getSSID();
	            int ip = info.getIpAddress();
	            String mac = info.getMacAddress();
	            result = strength + "|" + IntToIp(ip) + "|" + mac + "|" + ssid;
	        }
	        return result;
	    }
	 private static String IntToIp(int paramInt)
	    {
	        return (paramInt & 0xFF) + "." + (0xFF & paramInt >> 8) + "." + (0xFF & paramInt >> 16) + "." + (0xFF & paramInt >> 24);
	    }
}

2:此时的AndroidMainfest文件 (记得增加开机自启权限以及添加reciever)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.getInfo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="25" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".ThirdActivity"
            android:label="@string/app_name" >
        </activity>

        <receiver  android:name=".BootBroadcastReceiver">     
            <intent-filter>
               <action android:name="android.intent.action.BOOT_COMPLETED"/>     
            </intent-filter>      
        </receiver>
        
    </application>

</manifest>

可以看到此时是没有MainActivity的,并且BootBroadcastReciever类已报错,此处的MainActivity填入VR的MainActivity。例如Pico的是在vractivity.jar包里。使用com.XXX.UnityPicoNative.class.需要先导入jar包到Eclipse中

 

3:导出jar到Unity

说明:在没有MainActivity的情况下打包APK是无法安装运行的,这里是已有PicoVR作为主Activity。所以直接导入jar并打包APK

 

2019.07.25日更新

今天在做重启功能,很顺利的找到一篇文章。测试过OK

https://www.jianshu.com/p/c90f25539302 

AndroidSdutio或者Eclipse里函数

public void doRestart(int Ntime)
    {
         Log.d("Unity", "========restart "+Ntime);

        Intent restartIntent = getPackageManager()
                .getLaunchIntentForPackage(getPackageName() );
        PendingIntent intent = PendingIntent.getActivity(this, 0,restartIntent,0);
        AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        manager.set(AlarmManager.RTC, System.currentTimeMillis()+Ntime, intent);
        finish();
        android.os.Process.killProcess(android.os.Process.myPid());
    }

Unity调用

 public static void Restart(int delay)
  {
    AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    AndroidJavaObject mainActivity = jc.GetStatic<AndroidJavaObject>("currentActivity");
    mainActivity.Call("doRestart", delay);
    jc.Dispose();
    mainActivity.Dispose();
  }

上面能成功的前提是,你有一个MainActivity。通常建立一个Android工程,里面就有MainActivity。

这一段我也说了是用第三方的SDK。因此我没有MainActivity。所有都是静态调用

因此Eclipse代码修改如下

public static void doRestart()
	    {
	         
	        Intent restartIntent = (UnityPlayer.currentActivity.getApplicationContext()).getPackageManager().getLaunchIntentForPackage((UnityPlayer.currentActivity.getApplicationContext()).getPackageName() );
	        PendingIntent intent = PendingIntent.getActivity((UnityPlayer.currentActivity.getApplicationContext()), 0,restartIntent,0);
	        AlarmManager manager = (AlarmManager) (UnityPlayer.currentActivity.getApplicationContext()).getSystemService(Context.ALARM_SERVICE);
	        manager.set(AlarmManager.RTC, System.currentTimeMillis()+1, intent);
	        UnityPlayer.currentActivity.finish();
	        android.os.Process.killProcess(android.os.Process.myPid());
	    }

精髓就在于  UnityPlayer.currentActivity.getApplicationContext() 。等于Context

细心的你也注意到。doRestart()并没有参数。对的,使用第三方静态调用的时候加了参数并没有成功

AndroidJavaClass jc2 = new AndroidJavaClass("com.pico.hasai.ThirdActivity");
//"com.pico.hasai"  包名
//ThirdActivity一个java脚本。无任何继承。作为被调用的管理类
jc2.CallStatic("doRestart");
jc2.Dispose();

到此。重启功能完毕。开心

 

未解决问题:

1:开机自启的时间太长。(推测和手机性能有关,和一体机初始化引导有关)

2:没有MainAvtivity或未知情况下,无法重写里面的keydown事件等。例如一直亮屏

 

参考链接:

1:https://blog.csdn.net/qq_26999509/article/details/78444163  获取手机电量信息、网络状况

2:http://www.cnblogs.com/wuzhang/p/wuzhang20170318.html#commentform    Unity获取安卓手机运营商,电量,wifi信号

3:https://blog.csdn.net/weixin_39706415/article/details/84571421  无法获取wifi ssid (unknow ssid)解决方案

4:http://dev.picovr.com/   PicoVR开发者平台

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值