InterSystems EnsembleのAndroidでの交通警察罰金の例に関する通知のプッシュ





罰金を認識して支払うことができる多くのモバイルアプリケーションでは、新しい罰金に関する情報を受け取ることができます。 これを行うには、プッシュ通知のクライアントデバイスへの送信を使用すると便利です。



罰金を支払う申請も例外ではありませんでした。 サーバーパーツはEnsembleプラットフォームに実装されています。このプラットフォームでは、バージョン2015.1から、プッシュ通知の組み込みサポートが予定どおりに登場しました。



まず、少しの理論



プッシュ通知は、確立されたパラメーターに基づいてデータがプロバイダーからユーザーに届くときに情報を広める方法の1つです。



一般に、モバイルデバイスの場合、通知プロセスは次のようになります。











ユーザーにモバイルアプリケーションを通知するために、デバイスが受信するデータである通知配信サービスが使用されます。 そのため、通知を送信できません。 ユーザーは、プッシュ通知チャネルまたは特定のアプリケーションからの通知にサブスクライブする必要があります。



Ensembleには、プッシュ通知を操作するための次のエンティティがあります。



» EnsLib.PushNotifications.GCM.Operation -Google Cloud Messaging Services(GCM)サーバーにプッシュ通知を送信するためのビジネスオペレーション。 また、この操作により、複数のデバイスで1つのメッセージをアプリケーションに一度に送信できます。



» EnsLib.PushNotifications.APNS.Operationは、Apple Push Notificationsサーバーに通知を送信するビジネストランザクションです。 実装された各アプリケーションにメッセージを送信するには、別個のSSL証明書が必要です。



» EnsLib.PushNotifications.IdentityManager-アンサンブルビジネスプロセス。 ユーザーのデバイスの数と種類を考慮することなく、ユーザーにメッセージを送信できます。 基本的に、Identity Managerには、すべてのデバイスを1つのユーザーIDにマップするテーブルが含まれています。 Identity Managerビジネスプロセスは他の製品コンポーネントからメッセージを受信し、ルーターに転送します。ルーターはすべてのGCMメッセージをGCM操作に送信し、各APNSメッセージを対応するSSL証明書で構成されたAPNS操作に送信します。



» EnsLib.PushNotifications.AppService-製品の外部で生成されたプッシュメッセージを送信できるビジネスサービス。 実際、製品に関係なく、メッセージ自体はEnsemble内のどこかで生成できますが、サービスではこれらのメッセージをEnsembleから送信できます。 これらのクラスはすべて、Ensembleのドキュメント「 Ensembleプッシュ通知の構成と使用 」で詳しく説明されています。



通知プロセスの実装方法について



この場合、メッセージは製品内の特別に開発されたビジネスプロセスによって生成されるため、このサービスは役に立ちませんでした。 また、この段階ではAndroidアプリケーションしかないため、APNS操作もまだ使用していません。 実際、GCM操作を介して直接送信するには、最下位レベルの方法を使用しました。 将来的には、iOSバージョンのアプリケーションを実装するときに、Identity Managerを介した通知を使用した作業を実装すると、デバイスの種類と数を分析する必要がなくなります。 しかし、GCMについて詳しく説明しましょう。



通知を送信するには、製品内にプロセスを実装し、目的のビジネスオペレーションを接続する必要があります。 現在、プッシュ通知を送信するための2つの個別のプロセスがあり、それぞれ独自のロジックがあります:新しい罰金の通知、罰金の割引の期限切れの通知。 各タイプについてもう少し説明します。



最初に、すべての通知が機能するために必要な一般的なデータスキームと設定について説明します。





NotificationProtocol:HTTP

PushServer: http ://android.googleapis.com/gcm/send



最後の操作設定は次のようになります。









クライアントの識別子、デバイス(識別子とタイプ)、ドキュメントのリスト(運転免許証と自動車登録証明書)を保存する必要があります。 通知をサブスクライブするときに、クライアントからのリクエストでこれらすべての情報を受け取ります。 したがって、クラスが必要です。



クライアント-クライアントの保存用、アプリ-デバイスの保存用、ドキュメント-ドキュメントデータの保存用:



Class penalties.Data.Doc Extends %Persistent { ///  (  ) Property type As %String; ///  Property value As %String; } Class penalties.Data.App Extends %Persistent { ///  (GCM  APNS) Property Type As %String; ///  Property ID As %String(MAXLEN = 2048); } Class penalties.Data.Client Extends %Persistent { ///     Google Play Services,    Property Email As %String; ///   Property AppList As list Of penalties.Data.App; /// ,     Property Docs As list Of penalties.Data.Doc; }
      
      





新しい罰金の通知を送信するには、どの罰金をクライアントに送信するか、およびアプリケーションに入るときに彼がすでに見た罰金を理解する必要があります。 これを行うために、NotificationFlowクラスがあります。このクラスでは、クライアントはすでに罰金に関する情報を受け取っていることに注意してください。



 Class penalties.Data.NotificationFlow Extends %Persistent { ///  (   email) Property Client As %String; ///  Property Penalty As %String; ///   Property Sent As %Boolean; }
      
      





便宜上、クラスに言及するときは以下のパッケージ名を省略します。 クラスの内容により、新しい罰金のプロセスがどのように見えるかが明確になります。各クライアントについて、ドキュメントのリストを調べ、GIS GMP(州および地方自治体の支払いに関する州情報システム)で罰金の要求を行い、見つかった場合はNotificationFlowで利用可能な罰金を確認します-リストから削除します。その結果、クライアントに通知する必要がある罰金のリストを作成し、クライアントデバイスのリストを確認して、それぞれにプッシュ通知を送信します。



トップレベル:









ここで、clientkeyはコンテキストプロパティであり、そのデフォルト値は、Clientクラスに格納されたサブスクリプションを持つ最初の順序のクライアントの識別子です。



サブプロセスは次のようになります。









foreachブロックの内部を見てください。









このforeachブロックの後、準備が整ったEnsLib.PushNotifications.NotificationRequestリクエストがあり、メッセージテキストを追加するために残ります。 これは、ドキュメントのforeachブロックで行われます。









そして、リクエストデータを埋める小さなコード:



 ClassMethod getPenaltyforNotify(client As penalties.Data.Client, penaltyResponse As penalties.Operations.Response.getPenaltiesResponse, notificationRequest As EnsLib.PushNotifications.NotificationRequest) { set json="",count=0 set key="" for { set value=penaltyResponse.penalties.GetNext(.key) quit:key="" set find=0 set res=##class(%ResultSet).%New("%DynamicQuery:SQL") set exec="SELECT * FROM penalties_Data.NotificationFlow WHERE (Penalty = ?) AND (Client = ?)" set status=res.Prepare(exec) set status=res.Execute(value.billNumber,client.Email) if $$$ISERR(status) do res.%Close() kill res continue while res.Next() { if res.Data("Sent") set find=1 } do res.%Close() kill res if find {do penaltyResponse.penalties.RemoveAt(key), penaltyResponse.penalties.GetPrevious(.key)} else { set count=count+1 do notificationRequest.Data.SetAt("single","pushType") for prop="billNumber","billDate","validUntil","amount","addInfo","driverLicence","regCert" { set json=$property(value,prop) set json=$tr(json,"""","") if json="" continue do notificationRequest.Data.SetAt(json,prop) } set json="" set notObj=##class(penalties.Data.NotificationFlow).%New() set notObj.Client=client.Email set notObj.Penalty=value.billNumber set notObj.Sent=1 do notObj.%Save() } } if count>1 { set keyn="" for { do notificationRequest.Data.GetNext(.keyn) quit:keyn="" do notificationRequest.Data.RemoveAt(keyn) } do notificationRequest.Data.SetAt("multiple","pushType") do notificationRequest.Data.SetAt(count,"penaltiesCount") } }
      
      





罰金の支払いの割引のプロセスは、多少異なる方法で実装されます。 トップレベルで:









割引のある罰金の選択は、次のコードによって実行されます。



 ClassMethod getSaleforNotify() { //      kill ^mtempArray set res=##class(%ResultSet).%New("%DynamicQuery:SQL") //        set exec="SELECT * FROM penalties_Data.Penalty WHERE status!=2 AND addInfo LIKE '%%'" set status=res.Prepare(exec) set status=res.Execute() if $$$ISERR(status) do res.%Close() kill res quit while res.Next() { set discDate=$piece(res.Data("addInfo")," 50%   : ",2) set discDate=$extract(discDate,1,10) set date=$zdh(discDate,3) set dayscount=date-$p($h,",") //   5,2,1  0  if '$lf($lb(5,2,1,0),dayscount) continue set doc=$s(res.Data("regCert")'="":"sts||"_Res.Data("regCert"),1:"vu||"_Res.Data("driverLicence")) set clRes=##class(%ResultSet).%New("%DynamicQuery:SQL") // ,    set clExec="SELECT * FROM penalties_Data.Client WHERE (Docs [ ?)" set clStatus=clRes.Prepare(clExec) set clStatus=clRes.Execute(doc) if $$$ISERR(clStatus) do clRes.%Close() kill clRes quit while clRes.Next() { //  ,      set ^mtempArray($job,clRes.Data("Email"),res.Data("billNumber"))=res.Data("billDate") } do clRes.Close() } do res.Close() }
      
      





出口には、顧客による罰金の内訳を含むグローバルがあります。 今、あなたはこのグローバルを調べて、彼がまだ他のどこかに支払われていないことを確認した後、各クライアントに彼の罰金を送る必要があります:









罰金のサイクルに陥る:









実際には、プロセスの違いは次のとおりです。最初のケースでは、すべての顧客を確実に調査します。2番目のケースでは、特定のタイプの罰金を持つ顧客のみを選択します。 最初のケースでは、いくつかのペナルティーについて、合計金額(1日で多くのペナルティーを拾うことができるクライアントがいます)を含む1つの通知を送信します。

デバッグの過程で、メッセージの小さな機能に遭遇したため、いくつかのシステムメソッドを再定義する必要がありました。 メッセージのパラメーターの1つである罰金の数を渡します。これは一般的には「12345678901234567890」のようなものです。 通知を送信する操作のシステムクラスはそのような文字列を数値に変換しますが、残念ながら、GCMサービスはこのような大きな数値を受信した後、困惑して「Bad Request」を返します。



したがって、操作のシステムクラスを再定義し、その中でConvertArrayToJSONメソッドを呼び出します。その中で、2番目のパラメーターを0に設定して..Quoteを呼び出します。つまり、数字のみで構成される文字列を数字に変換せず、文字列のままにします。



 Method ConvertArrayToJSON(ByRef pArray) As %String { #dim tOutput As %String = "" #dim tSubscript As %String = "" For { Set tSubscript = $ORDER(pArray(tSubscript)) Quit:tSubscript="" Set:tOutput'="" tOutput = tOutput _ "," Set tOutput = tOutput _ ..Quote(tSubscript) _ ": " If $GET(pArray(tSubscript))'="" { #dim tValue = pArray(tSubscript) If $LISTVALID(tValue) { #dim tIndex As %Integer // $LIST .. aka an array // NOTE: This only handles an array of scalar values Set tOutput = tOutput _ "[ " For tIndex = 1:1:$LISTLENGTH(tValue) { Set:tIndex>1 tOutput = tOutput _ ", " Set tOutput = tOutput _ ..Quote($LISTGET(tValue,tIndex),0) } Set tOutput = tOutput _ " ]" } Else { // Simple string Set tOutput = tOutput _ ..Quote(tValue,1) } } Else { // Child elements #dim tTemp Kill tTemp Merge tTemp = pArray(tSubscript) Set tOutput = tOutput _ ..ConvertArrayToJSON(.tTemp) } } Set tOutput = "{" _ tOutput _ "}" Quit tOutput }
      
      





実装プロセス中に他の問題は見つかりませんでした。 合計、通知を送信するために行う主なこと:





実際には、それだけです。 既製のEnsembleコンポーネントを使用することで、プロセスの実装にはデバッグとテストを含めて数時間かかります。



出口では、タイムリーに新しい罰金を見つけ、時間通りに割引を覚えている顧客を満足させています。









AndroidおよびiOSアプリケーションでの動作を確認できます。



All Articles