【问题标题】:Android - Navigating through USSD menu using pre-determined inputs sent via requestsAndroid - 使用通过请求发送的预定输入浏览 USSD 菜单
【发布时间】:2019-03-25 03:17:26
【问题描述】:

我计划创建一个 Android 应用程序,该应用程序将自动向 USSD 菜单发送用户响应。只需单击一个按钮,应用就会发送初始代码,然后是其余的菜单输入。

例如,初始数字为 *143#,后跟 1、1、1 和用户 PIN。我希望能够自动化输入序列,这样用户就不必自己输入了。

我知道在 Android Oreo 中,他们使用 TelephonyManager 实现了 USSD 回调,Android 应用可以在其中发送 USSD 请求,然后读取给出的响应。

我目前正在探索该选项,这是我迄今为止尝试过的。 Heavily lifted from this StackOverflow Question.

interface UssdResultNotifiable {
    void notifyUssdResult(String request, String returnMessage, int resultCode);
}


public class MainActivity extends Activity implements UssdResultNotifiable {

    USSDSessionHandler hdl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onUssdSend(View view) {
        hdl = new USSDSessionHandler(MainActivity.this, MainActivity.this);
        hdl.doSession(((EditText) this.findViewById(R.id.ussdText)).getText().toString());
    }

    @Override
    public void notifyUssdResult(final String request, final String returnMessage, final int resultCode) {
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "Request was " + request + "\n response is "
                        + returnMessage + "\n result code is " + resultCode, Toast.LENGTH_LONG).show();

                Log.e(TAG, "ussd result hit! Response is = " + returnMessage);

                hdl.doSession("1");
            }
        });

    }

}

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;

                for (Method _m : methodList)
                    if (_m.getName().equals("handleUssdRequest")) {
                        handleUssdRequest = _m;
                        break;
                    }
            }
        }
    }

    @android.support.annotation.RequiresApi(api = Build.VERSION_CODES.N)
    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) {
                        Object p = ussdResponse.getParcelable("USSD_RESPONSE");

                        if (p != null) {

                            Method[] methodList = p.getClass().getMethods();
                            for(Method m : methodList){
                                Log.e(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();
        }
    }
}

你得到的是一个应用程序,它会为用户请求 USSD 输入,一旦点击“发送”按钮,USSD 响应就会通过notifyUssdResult 函数上的 Toast 显示。在同一个函数中,我发送序列中的下一个输入,即“1”。我能否再次向 USSD 发送回复,USSD 将其作为输入并进入下一个菜单。

但是,一旦我发送回复,USSD 菜单就会显示在我的设备中,我无法继续进行。我无法完全通过我的应用程序浏览 USSD 菜单,因为 USSD 菜单会干扰屏幕并且不会消失。

有什么可以参考的样本吗?

【问题讨论】:

  • 对这个有什么建议吗?我可以得到handleUssdRequest方法!
  • 不幸的是,handleUssdRequest API 不适用于多步骤 USSD 会话。由于大多数电信公司在拨号时阻止连接,这使得它除了检查余额之外毫无用处

标签: android telephony telephonymanager ussd


【解决方案1】:

例如,您要运行 *123# 1 then 1 then 1 then 2 所以你可以直接用字符串写这个是代码希望它有帮助

String s= "*123*1*1*2#"
            //screen   from  which  can get the number
            if((s.startsWith("*"))&&(s.endsWith("#"))){
                //if true then it is a USSD call----
                callstring=s.substring(0, s.length()-1);
                callstring=callstring+ Uri.encode("#");

                Log.d("CALL TYPE---------->", "USSD CALL");


            }else{
                callstring=s;
                Log.d("CALL TYPE---------->", "Not a USSD CALL");

            }
            Intent i=new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+callstring));
            startActivity(i);

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多