Xamarin Android 对来电和去电做出反应
Xamarin Android React to Incoming and Outgoing calls
我想对设备上的呼叫(传入和传出)做出反应。主要问题是监视 Phone.State 的广播接收器从不接收有关传入和传出呼叫的通知,因此用于在日志中记录呼叫信息的代码永远不会执行。
我还尝试了 Whosebug 上与广播接收器相关的大部分链接,但其中 none 似乎有效。
这是我当前的源代码;
[assembly: UsesPermission(Manifest.Permission.ReadCallLog)]
[assembly: UsesPermission(Manifest.Permission.ReadPhoneNumbers)]
[assembly: UsesPermission(Manifest.Permission.ReadPhoneState)]
[assembly: UsesPermission(Manifest.Permission.ProcessOutgoingCalls)]
[assembly: UsesPermission(Manifest.Permission.ReadExternalStorage)]
[assembly: UsesPermission(Manifest.Permission.WriteExternalStorage)]
namespace IncomingOutgoingCall
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
#region Private Properties
IncomingOutgoingBroadcastReceiver callReceiver;
int REQUEST_PERMISSION_CODE = 1003;
#endregion
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
RequestPermission(Manifest.Permission.ReadPhoneState, Manifest.Permission.ProcessOutgoingCalls, Manifest.Permission.ReadPhoneNumbers, Manifest.Permission.WriteExternalStorage, Manifest.Permission.ReadExternalStorage);
callReceiver = new IncomingOutgoingBroadcastReceiver();
var callMonitorIntent = new Intent(ApplicationContext, typeof(IncomingOutgoingBroadcastReceiver));
// SendBroadcast(callMonitorIntent);
}
public void RequestPermission(params string[] permissions)
{
// Request required permission
ActivityCompat.RequestPermissions(this, permissions, REQUEST_PERMISSION_CODE);
}
}
[BroadcastReceiver(Name = "com.callmonitor.app.IncomingOutgoingBroadcastReceiver", Enabled = true, Exported = false)]
[IntentFilter(new[] { TelephonyManager.ActionPhoneStateChanged, "android.intent.action.PHONE_STATE", "android.intent.action.NEW_OUTGOING_CALL" }, Priority = (int)IntentFilterPriority.HighPriority)]
public class IncomingOutgoingBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
string dirPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/" + AppInfo.Name;
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
string filePath = Path.Combine(dirPath, "logFile.txt");
if (!File.Exists(filePath))
File.Create(filePath);
using (StreamWriter sw = new StreamWriter(filePath))
{
// Code to register call information omitted
}
}
}
}
}
这是我的 android 清单文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.callmonitor" android:installLocation="auto">
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="27" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:label="CallMonitor"></application>
</manifest>
如果有人有 link/suggestion 关于如何让我的广播接收器在每次通话进行时工作的经过测试和工作的解决方案,我想尝试一下。
从 BroadcastReceiver 读取 phone 调用日志似乎并不容易,读取 phone 调用日志的最佳方法是通过 Cursor 从 Android 数据库读取。
public IEnumerable<CallLogModel> GetCallLogs()
{
var phoneContacts = new List<CallLogModel>();
// filter in desc order limit by no
string querySorter = String.Format("{0} desc ", CallLog.Calls.Date);
using (var phones = Android.App.Application.Context.ContentResolver.Query(CallLog.Calls.ContentUri, null, null, null, querySorter))
{
if (phones != null)
{
while (phones.MoveToNext())
{
try
{
string callNumber = phones.GetString(phones.GetColumnIndex(CallLog.Calls.Number));
string callDuration = phones.GetString(phones.GetColumnIndex(CallLog.Calls.Duration));
long callDate = phones.GetLong(phones.GetColumnIndex(CallLog.Calls.Date));
string callName = phones.GetString(phones.GetColumnIndex(CallLog.Calls.CachedName));
int callTypeInt = phones.GetInt(phones.GetColumnIndex(CallLog.Calls.Type));
string callType = Enum.GetName(typeof(CallType), callTypeInt);
var log = new CallLogModel();
log.CallName = callName;
log.CallNumber = callNumber;
log.CallDuration = callDuration;
log.CallDateTick = callDate;
log.CallType = callType;
phoneContacts.Add(log);
}
catch (Exception ex)
{
//something wrong with one contact, may be display name is completely empty, decide what to do
}
}
phones.Close();
}
// if we get here, we can't access the contacts. Consider throwing an exception to display to the user
}
return phoneContacts;
}
这是您可以查看的示例:
我想对设备上的呼叫(传入和传出)做出反应。主要问题是监视 Phone.State 的广播接收器从不接收有关传入和传出呼叫的通知,因此用于在日志中记录呼叫信息的代码永远不会执行。 我还尝试了 Whosebug 上与广播接收器相关的大部分链接,但其中 none 似乎有效。 这是我当前的源代码;
[assembly: UsesPermission(Manifest.Permission.ReadCallLog)]
[assembly: UsesPermission(Manifest.Permission.ReadPhoneNumbers)]
[assembly: UsesPermission(Manifest.Permission.ReadPhoneState)]
[assembly: UsesPermission(Manifest.Permission.ProcessOutgoingCalls)]
[assembly: UsesPermission(Manifest.Permission.ReadExternalStorage)]
[assembly: UsesPermission(Manifest.Permission.WriteExternalStorage)]
namespace IncomingOutgoingCall
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
#region Private Properties
IncomingOutgoingBroadcastReceiver callReceiver;
int REQUEST_PERMISSION_CODE = 1003;
#endregion
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
RequestPermission(Manifest.Permission.ReadPhoneState, Manifest.Permission.ProcessOutgoingCalls, Manifest.Permission.ReadPhoneNumbers, Manifest.Permission.WriteExternalStorage, Manifest.Permission.ReadExternalStorage);
callReceiver = new IncomingOutgoingBroadcastReceiver();
var callMonitorIntent = new Intent(ApplicationContext, typeof(IncomingOutgoingBroadcastReceiver));
// SendBroadcast(callMonitorIntent);
}
public void RequestPermission(params string[] permissions)
{
// Request required permission
ActivityCompat.RequestPermissions(this, permissions, REQUEST_PERMISSION_CODE);
}
}
[BroadcastReceiver(Name = "com.callmonitor.app.IncomingOutgoingBroadcastReceiver", Enabled = true, Exported = false)]
[IntentFilter(new[] { TelephonyManager.ActionPhoneStateChanged, "android.intent.action.PHONE_STATE", "android.intent.action.NEW_OUTGOING_CALL" }, Priority = (int)IntentFilterPriority.HighPriority)]
public class IncomingOutgoingBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
string dirPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/" + AppInfo.Name;
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
string filePath = Path.Combine(dirPath, "logFile.txt");
if (!File.Exists(filePath))
File.Create(filePath);
using (StreamWriter sw = new StreamWriter(filePath))
{
// Code to register call information omitted
}
}
}
}
}
这是我的 android 清单文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.callmonitor" android:installLocation="auto">
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="27" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:label="CallMonitor"></application>
</manifest>
如果有人有 link/suggestion 关于如何让我的广播接收器在每次通话进行时工作的经过测试和工作的解决方案,我想尝试一下。
从 BroadcastReceiver 读取 phone 调用日志似乎并不容易,读取 phone 调用日志的最佳方法是通过 Cursor 从 Android 数据库读取。
public IEnumerable<CallLogModel> GetCallLogs()
{
var phoneContacts = new List<CallLogModel>();
// filter in desc order limit by no
string querySorter = String.Format("{0} desc ", CallLog.Calls.Date);
using (var phones = Android.App.Application.Context.ContentResolver.Query(CallLog.Calls.ContentUri, null, null, null, querySorter))
{
if (phones != null)
{
while (phones.MoveToNext())
{
try
{
string callNumber = phones.GetString(phones.GetColumnIndex(CallLog.Calls.Number));
string callDuration = phones.GetString(phones.GetColumnIndex(CallLog.Calls.Duration));
long callDate = phones.GetLong(phones.GetColumnIndex(CallLog.Calls.Date));
string callName = phones.GetString(phones.GetColumnIndex(CallLog.Calls.CachedName));
int callTypeInt = phones.GetInt(phones.GetColumnIndex(CallLog.Calls.Type));
string callType = Enum.GetName(typeof(CallType), callTypeInt);
var log = new CallLogModel();
log.CallName = callName;
log.CallNumber = callNumber;
log.CallDuration = callDuration;
log.CallDateTick = callDate;
log.CallType = callType;
phoneContacts.Add(log);
}
catch (Exception ex)
{
//something wrong with one contact, may be display name is completely empty, decide what to do
}
}
phones.Close();
}
// if we get here, we can't access the contacts. Consider throwing an exception to display to the user
}
return phoneContacts;
}
这是您可以查看的示例: