USSD 杂记
作者:互联网
Android Oreo允许应用程序读取来自运营商的USSD消息。
利用emoney执行话费充值,需要执行USSD代码,尝试编写apk执行ussd代码进行充值。
尝试在Android8的系统上进行USSD session交互,发现暂时没有解决方案。。。。
尝试一次性发送所有USSD,*123*1*5*1256#,发现如果到了需要输入类似密码之类的自定义字符串时,会失败。
只能发送第一个USSD代码,无法进行后续的菜单交互。如果只需要调用USSD获取话费余额、套餐情况的请拿走。
代码如下:
package com.zongh.dbussd; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; import android.telecom.TelecomManager; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.Switch; import android.widget.Toast; import android.support.design.widget.Snackbar; import android.support.annotation.RequiresApi; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import static android.content.ContentValues.TAG; interface UssdResultNotifiable { void notifyUssdResult(String request, String returnMessage, int resultCode); } public class HomeActivity extends Activity implements UssdResultNotifiable { USSDSessionHandler hdl; private TelephonyManager telephonyManager; private PhoneCallListener listener; private TelecomManager telecomManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); } public void onUssdSend(View view) { //USSDHandler callback = new USSDHandler(view); /* if (checkSelfPermission(Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { *//*if(ActivityCompat.shouldShowRequestPermissionRationale(HomeActivity.this, Manifest.permission.CALL_PHONE)) { } else {*//* //ActivityCompat.requestPermissions(HomeActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 0); // } Snackbar.make(view, "permissions were missing", Snackbar.LENGTH_LONG) .setAction("Response", null).show(); return; }*/ //HomeActivity.this.telephonyManager.sendUssdRequest("*#123*99#", callback, new Handler()); hdl = new USSDSessionHandler(HomeActivity.this, HomeActivity.this); hdl.doSession(((EditText)this.findViewById(R.id.ussdText)).getText().toString()); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. // getMenuInflater().inflate(R.menu.menu_home, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement // if (id == R.id.action_settings) { // return true; // } return super.onOptionsItemSelected(item); } public void toggleListener(View v) { if (((Switch) v).isChecked()) { this.listenForTelephony(); Toast.makeText(this, "Listening for calls", Toast.LENGTH_LONG).show(); } else { this.stopListeningForTelephony(); } } private void listenForTelephony() { this.telephonyManager = (TelephonyManager) this.getSystemService(this.TELEPHONY_SERVICE); this.telecomManager = (TelecomManager) this.getSystemService(this.TELECOM_SERVICE); this.listener = new PhoneCallListener(); telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE); } private void stopListeningForTelephony() { this.telephonyManager = null; this.telecomManager = null; } @Override public void notifyUssdResult(final String request, final String returnMessage, final int resultCode) { this.runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(HomeActivity.this, "Request was " + request + "\n response is " + returnMessage + "\n result code is " + resultCode, Toast.LENGTH_LONG).show(); } }); } class PhoneCallListener extends PhoneStateListener { @RequiresApi(api = Build.VERSION_CODES.M) @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { case TelephonyManager.CALL_STATE_RINGING: HomeActivity.this.telecomManager.acceptRingingCall(); break; case TelephonyManager.CALL_STATE_IDLE: Toast.makeText(HomeActivity.this, "Call is no longer active...", Toast.LENGTH_LONG); break; } } } @TargetApi(Build.VERSION_CODES.O) class USSDHandler extends TelephonyManager.UssdResponseCallback { View parent; USSDHandler(View v) { this.parent = v; } @Override public void onReceiveUssdResponse(TelephonyManager telephonyManager, String request, CharSequence response) { super.onReceiveUssdResponse(telephonyManager, request, response); Snackbar.make(this.parent, response, Snackbar.LENGTH_LONG) .setAction("Response", null).show(); } @Override public void onReceiveUssdResponseFailed(TelephonyManager telephonyManager, String request, int failureCode) { super.onReceiveUssdResponseFailed(telephonyManager, request, failureCode); Snackbar.make(this.parent, "error is " + failureCode + " for req " + request, Snackbar.LENGTH_LONG) .setAction("Response", null).show(); } } } class USSDSessionHandler { TelephonyManager tm; private UssdResultNotifiable client; private Method handleUssdRequest; private Object iTelephony; USSDSessionHandler(Context parent, UssdResultNotifiable client) { this.client = client; this.tm = (TelephonyManager) parent.getSystemService(Context.TELEPHONY_SERVICE); try { this.getUssdRequestMethod(); } catch (Exception ex) { //log } } private void getUssdRequestMethod() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { if (tm != null) { Class telephonyManagerClass = Class.forName(tm.getClass().getName()); if (telephonyManagerClass != null) { Method getITelephony = telephonyManagerClass.getDeclaredMethod("getITelephony"); getITelephony.setAccessible(true); this.iTelephony = getITelephony.invoke(tm); // Get the internal ITelephony object Method[] methodList = iTelephony.getClass().getMethods(); this.handleUssdRequest = null; /* * Somehow, the method wouldn't come up if I simply used: * iTelephony.getClass().getMethod('handleUssdRequest') */ for (Method _m : methodList) if (_m.getName().equals("handleUssdRequest")) { handleUssdRequest = _m; break; } } } } public void doSession(String ussdRequest) { try { if (handleUssdRequest != null) { handleUssdRequest.setAccessible(true); handleUssdRequest.invoke(iTelephony, SubscriptionManager.getDefaultSubscriptionId(), ussdRequest, new ResultReceiver(new Handler()) { @Override protected void onReceiveResult(int resultCode, Bundle ussdResponse) { /* * Usually you should the getParcelable() response to some Parcel * child class but that's not possible here, since the "UssdResponse" * class isn't in the SDK so we need to * reflect again to get the result of getReturnMessage() and * finally return that! */ Object p = ussdResponse.getParcelable("USSD_RESPONSE"); if (p != null) { Method[] methodList = p.getClass().getMethods(); for(Method m : methodList) { Log.i(TAG, "onReceiveResult: " + m.getName()); } try { CharSequence returnMessage = (CharSequence) p.getClass().getMethod("getReturnMessage").invoke(p); CharSequence request = (CharSequence) p.getClass().getMethod("getUssdRequest").invoke(p); USSDSessionHandler.this.client.notifyUssdResult("" + request, "" + returnMessage, resultCode); //they could be null } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } } }); } } catch (IllegalAccessException | InvocationTargetException e1) { e1.printStackTrace(); } } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".HomeActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="USSD Input" android:textSize="18sp" /> <EditText android:id="@+id/ussdText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:ems="10" android:inputType="textPersonName" /> </LinearLayout> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onUssdSend" android:text="send" /> </LinearLayout>
标签:USSD,void,TelephonyManager,杂记,import,android,null,public 来源: https://www.cnblogs.com/dbxiaobai/p/10586849.html