若小笨蛋 發表於 2023-5-12 10:36:00

MAUI开发Android程序使PDA扫码广播消息转发至Web页面

<h2 id="前言">前言</h2>
<p>公司系统的手持终端(PDA)是用的Vue写的前端代码<br>
在PDA上用浏览器直接打开Web页面<br>
PDA扫码的时候,输出模式直接用模拟键盘按键的方式输出<br>
这样在Web页面上,如果一个输入框在当前有焦点的情况下<br>
PDA扫码的内容会直接填充至对应的输入框<br>
正常的话这样没有问题</p>
<p>但是最近有一个项目,PDA不是我们提供。<br>
而是使用现有PDA,要把我们的系统在现有PDA上使用<br>
但是现有PDA使用的扫码输出方式是用的Andorid广播</p>
<p>因为现有PDA不只有我们一家系统,所以不能修改扫码输出方式<br>
这样就使得我们不得不对系统进行改造</p>
<p><img src="https://img2023.cnblogs.com/blog/45026/202305/45026-20230512103354493-474979938.png" alt="" loading="lazy"><br>
<img src="https://img2023.cnblogs.com/blog/45026/202305/45026-20230512103404428-1600393721.png" alt="" loading="lazy"></p>
<h2 id="思考方法">思考方法</h2>
<p>因为系统已经使用Vue框架已经开发好的。不可能为了这么点事情<br>
把PDA上的系统全用Android重新来开发一次,那样成本太大</p>
<p>所以想的办法也很简单。<br>
就是做一个Andorid的程序套壳,然后在程序里使用WebView加载现有系统<br>
这样在Andorid程序里接收PDA扫码的广播信号<br>
然后收到信号后,把扫码到的内容使用WebView的JavaScript调用方式<br>
传输到Web页面接收。<br>
这样就实现了在Web页面上接收Andorid的广播消息功能</p>
<h2 id="实现过程">实现过程</h2>
<p>因为我们没有Andorid的开发人员,<br>
只有前端的NodeJs和后端的.Net开发人员<br>
所以开发Android程序框架也很自然<br>
只能是.Net开发人员使用 Xamarin.Android 或者 MAUI 这两种方式</p>
<p>因为只是一个Android的程序套壳,界面也不是很难<br>
所以就当一次小试验,自然也就想尝试一下微软最新的MAUI了</p>
<h3 id="安装maui">安装MAUI</h3>
<p>因为我们原来开发没有使用过MAUI,虽然机器上有VS2022<br>
但是也要添加MAUI的开发功能<br>
安装MAUI参考链接<br>
<img src="https://img2023.cnblogs.com/blog/45026/202305/45026-20230512103415424-1086898103.png" alt="" loading="lazy"></p>
<h3 id="创建maui应用">创建MAUI应用</h3>
<p>参照微软的文档一步步操作创建MAUI应用<br>
创建MAUI应用参考链接</p>
<h3 id="在主界面添加webview">在主界面添加WebView</h3>
<p><img src="https://img2023.cnblogs.com/blog/45026/202305/45026-20230512103423688-1285674855.png" alt="" loading="lazy"></p>
<p>WebView参考文档</p>
<p>我们设置WebView的浏览地址为我们系统的Web地址<br>
此处设置为:http://10.76.99.70:8081/</p>
<p>把MainPage.xaml文件修改如下</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="WMS.RFWrap.MainPage"&gt;

    &lt;ScrollView&gt;
      &lt;StackLayout&gt;
            &lt;WebView x:Name="mainWeb" Source="http://10.76.99.70:8081/" VerticalOptions="FillAndExpand"&gt;&lt;/WebView&gt;
      &lt;/StackLayout&gt;
    &lt;/ScrollView&gt;

&lt;/ContentPage&gt;
</code></pre>
<h3 id="接收android广播消息">接收Android广播消息</h3>
<p>在Platforms.Andorid目录下创建广播消息接收代码<br>
其中,IntentFilter设置的值要与PDA上配置的广播消息代码一至</p>
<pre><code class="language-C#">namespace WMS.RFWrap.Platforms.Android;


{ "android.intent.ACTION_DECODE_DATA" })]
public class ScanBroadcastReceiver : BroadcastReceiver
{
    private Action&lt;string&gt; ScanDataAccepted;
    public ScanBroadcastReceiver()
    {

    }
    public ScanBroadcastReceiver(Action&lt;string&gt; action)
    {
      this.ScanDataAccepted = action;
    }
    public override void OnReceive(Context context, Intent intent)
    {
      var value = intent.GetStringExtra("barcode_string");
      ScanDataAccepted?.Invoke(value);
    }
}
</code></pre>
<p>在Platforms.Andorid.MainActivity.cs文件注册广播接收</p>
<pre><code class="language-C#">public class MainActivity : MauiAppCompatActivity
{
    public ScanBroadcastReceiver scanReceiver { get; set; }
    /// &lt;summary&gt;
    /// 委托事件
    /// &lt;/summary&gt;
    public static Action&lt;string&gt; ScanDeviceRecevied;
    protected override void OnCreate(Bundle savedInstanceState)
    {
      base.OnCreate(savedInstanceState);
      scanReceiver = new ScanBroadcastReceiver((barcode) =&gt;
      {
            ScanDeviceRecevied?.Invoke(barcode);
      });
    }
    protected override void OnResume()
    {
      base.OnResume();
      RegisterReceiver(scanReceiver, new Android.Content.IntentFilter("android.intent.ACTION_DECODE_DATA"));
    }
    protected override void OnPause()
    {
      UnregisterReceiver(scanReceiver);
      base.OnPause();
    }
}
</code></pre>
<p>在MainPage.xaml.cs文件里编写接收代码<br>
接收到广播扫码内容后,通过WebView的Eval方法来执行Web页面方法<br>
我们这里使用的是window.postMessage协议通讯<br>
window.postMessage参考文档<br>
我们调用postMessage方法,把内容传输到Web页面</p>
<pre><code class="language-C#">public partial class MainPage : ContentPage
{
    public MainPage()
    {
      InitializeComponent();
#if ANDROID
      //var mainActivity = Platform.CurrentActivity as MainActivity;
      MainActivity.ScanDeviceRecevied = (barcode) =&gt; {
            Console.WriteLine(barcode);
            OnScanBarcode(barcode);
      };
#endif
    }
    public void OnScanBarcode(string barcode)
    {
      if (mainWeb != null)
      {
            var data = new { type = "barcode", data = barcode };
            var json = JsonSerializer.Serialize(data);
            var script = $"postMessage({json},'*')";
            mainWeb.Eval(script);
      }
    }
}
</code></pre>
<p>在前端Vue页面接收WebView传过来的postMessage信号<br>
因为我们使用的是postMessage信号,所以在前端只要监听message事件就可以了<br>
message事件与Vue无关,所有Web页都可以使用<br>
然后在onScanMsg回调方法里面处理对应的数据,就能正常接收信息了<br>
window.addEventListener('message', onScanMsg)</p>
<pre><code class="language-javascript">&lt;template&gt;
&lt;router-view /&gt;
&lt;/template&gt;

&lt;script&gt;
import { provide, ref, reactive, toRaw, onMounted, onUnmounted } from 'vue'
import { useStore } from 'vuex'
export default {
setup() {
    const store = useStore() //使用store
    onMounted(() =&gt; {
      window.addEventListener('message', onScanMsg)
    })
    const onScanMsg = (e) =&gt; {
      console.log('onScanMsg', e)
      if (typeof e.data === 'object' &amp;&amp; e.data.type === 'barcode')
      store.commit('SET_SCANCODE', e.data.data)
    }
    return {}
}
}
&lt;/script&gt;

&lt;style&gt;
&lt;/style&gt;

</code></pre>
<p>本示例是接收到信息后,通过vuex设置全局Store值<br>
这样在要获取扫码的页面只用监听Store值变化,就可以接收到最新的扫码结果</p>
<pre><code class="language-javascript">&lt;template&gt;
&lt;van-nav-bar title="扫码" left-text="数据" left-arrow fixed placeholder @click-left="$router.replace({ path: '/Home/DataIndex' })" /&gt;
&lt;van-field v-model="scancode" label="数据" placeholder="请扫码" /&gt;
&lt;van-list&gt;
    &lt;van-cell-group&gt;
      &lt;van-cell v-for="item in list" :key="item" :title="item" /&gt;
    &lt;/van-cell-group&gt;
&lt;/van-list&gt;
&lt;/template&gt;

&lt;script&gt;
import { defineComponent, reactive, ref, toRefs, toRaw, onMounted, watch, computed, getCurrentInstance } from 'vue'
import { useStore } from 'vuex'
export default {
setup() {
    const store = useStore()//使用store
    const scancode = computed(() =&gt; store.getters.scancode)
    const list = ref([])
    watch(() =&gt; store.getters.scancode, (newValue) =&gt; {
      list.value.push(newValue)
    })
    return {
      scancode,
      list
    }
}
}
&lt;/script&gt;

&lt;style&gt;
&lt;/style&gt;
</code></pre>
<p>最终实现结果<br>
<img src="https://img2023.cnblogs.com/blog/45026/202305/45026-20230512103438486-1630209284.png" alt="" loading="lazy"></p>
<p><strong>强烈建议PDA设备厂商把 PDA广播信号 集成至 WebView</strong></p>


</div>
<div id="MySignature" role="contentinfo">
    都看完了,你确定不点个赞再走?<br><br>
来源:https://www.cnblogs.com/liuju150/p/MAUI-Android-PDA-BroadcastReceiver-WebView.html
頁: [1]
查看完整版本: MAUI开发Android程序使PDA扫码广播消息转发至Web页面