投稿

10月, 2019の投稿を表示しています

82bts.com からダウンロードした zipファイルが破損している→エラー部分を取り除く

イメージ
82bts.com からダウンロードした zipファイルが破損していたので、中身を覗いてみたらサイト側のエラーがファイルに入り込んでいたので削除 zipファイルをテキストエディタ(サクラエディタ)で開いて(バイナリエディタのほうがいいんだろうけど) PKより前にあるhtmlエラー部分を取り除く ファイル末尾もバイナリ部分が終わって、最初のhtmlタグ(<br />等)以降を取り除く 保存時に改行コードの混在はそのままにして保存(エディタによる)

Android 7 (Nougat)以降で、RINGER_MODE_VIBRATE(マナーモード)へ切り替えようとするとクラッシュ

久々に Google Play へ登録したアプリを更新しようとしたら、targetSdkVersion は 26 以上、2019/11/1以降は 28 以上じゃないとアップできねーとか表示されて、ターゲットをあげた途端に色々動作しなくなったり強制終了するようになったのメモ Android 7 (Nougat)以降で、RINGER_MODE_VIBRATE(マナーモード)へ切り替えようとすると値が AudioManager.RINGER_MODE_VIBRATE (値=1) の時のみエラーが発生 AudioManager AudioMan = (AudioManager) getSystemService(Context.AUDIO_SERVICE); AudioMan.setRingerMode(AudioManager.RINGER_MODE_VIBRATE); // ←バイブレートはNG // AudioMan.setRingerMode(AudioManager.RINGER_MODE_SILENT); // ←サイレントはOK どうも、バイブレートへ切り替えるのに権限と確認が 必要になったらしい マニフェストへ < uses-permission android :name ="android.permission.ACCESS_NOTIFICATION_POLICY" /> を加えて モード変更の手前で、権限が得られていない場合に設定画面を表示させる記述を入れる // Android7 以降 マナーモードへの権限設定(初回は設定画面が開く) NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !notificationManager.isNotificationPolicyAccessGranted()) { Intent setupIntent = new Intent(android.prov

Android 8 (Oreo) 以降で、透過Activityがクラッシュ

久々に Google Play へ登録したアプリを更新しようとしたら、targetSdkVersion は 26 以上、2019/11/1以降は 28 以上じゃないとアップできねーとか表示されて、ターゲットをあげた途端に色々動作しなくなったり強制終了するようになったのメモ SdkVersionを上げたら、通知から読んでいた 透過Activityがクラッシュするようになった protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ←ここで既に落ちてる } どこから呼び出しても落ちるため、調べていたら 透過Activityで画面の向きを固定設定していると Oreoでクラッシュ するという貴重な情報にたどり着く <activity android:name=".HogeActivity" android:screenorientation="portrait" android:theme="@android:style/Theme.Translucent.NoTitleBar"> <intent-filter> <action android:name="android.intent.action.MAIN"> </action></intent-filter> </activity> のように     android:screenOrientation="portrait" や     android:screenOrientation="landscape" と共に     android:theme="@android:style/Theme.NoDisplay" や     android:theme="@android:style/Theme.Translucent.NoTitleBar"

Android 8 (Oreo) 以降の通知生成

久々に Google Play へ登録したアプリを更新しようとしたら、targetSdkVersion は 26 以上、2019/11/1以降は 28 以上じゃないとアップできねーとか表示されて、ターゲットをあげた途端に色々動作しなくなったり強制終了するようになったのメモ Oreo以降の通知登録、Notification.Builder へ setChannelId を追加と NotificationChannel の利用が必須へ Android 8 (Oreo) 以降の通知生成 (わかりにくいので括弧で包んでます) // 通知をタップで起動するActivity Intent intent = new Intent(this, HogeActivity.class); // タップで呼ばれるActivity intent.putExtra("sendData", true); // Activityへ渡すデータ等(複数追加可) PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); // 通知生成 NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); { Notification.Builder nbuilder = new Notification.Builder(this); { nbuilder.setPriority(Notification.PRIORITY_DEFAULT); nbuilder.setContentTitle("タイトル"); nbuilder.setContentText("メッセージ");

GOM Player 終了時のブラウザ広告を止める(対策されました→再対応)

イメージ
【追記】2019/12/23 GOM Player 2.3.48.5310 あたりでこの記事の回避方法が対策されてしまいましたので →  ログイン時にレジストリの値をvbscriptで書き換える方法  へ移動してください GOM Player が終了時に既定のブラウザで広告を表示するようになった 広告を否定するつもりはないが、あまりにマナーが悪すぎる レジストリを調べると広告を表示した時刻を Unixtime で記録して、この値が24時間以上(たぶん)古いと広告を出しているようなので、値を未来へ変更 ※そのうち対策される可能性があります レジストリの変更手順 ファイル名を指定して実行(Win+R)で regedit を入力、レジストリエディタを起動 \HKEY_CURRENT_USER\Software\GRETECH\GomPlayer を開く EndingBrowser の値を 10進数で 1735657200 (2025/1/1)等の未来に設定

Delphi の TSplitter がアレなので TSpTBXSplitter を使ってみる

イメージ
Delphi の Splitterコンポーネント、サイズ変更のため使用するなら問題ないのだが、対象先がサイズ 0 になるような使い方の場合、スプリッタの移動やフォームのリサイズをきっかけに突然使用不能になったりする 適当なタイミングで、対象先とスプリッタ位置を修正したりしてみるが、対象がサイズ 0 の場合、位置関係がハッキリせず、問題が解消したりしなかったりと昔からイライラの素だったりした(現在も変わらない様子) で、ちょうど入れていた SpTBX のスプリッタを使ってみたら、位置関係不明の状態があっさり解決 MinSizeプロパティの解釈が違うので、ソコだけ修正した MinSize プロパティ TSplitter は、この値未満になると対象のサイズが 0になる サイズを規制するには対象の Constraints で指定 TSpTBXSplitter では、この値未満にはスプリッタが移動しなくなる 対象の Constraints 規制値が実行時に確認すると 0 にされてる で、TSplitter の MinSize プロパティと同じ動きは procedure TDocForm.SpTBXSplitter1Moved(Sender: TObject); begin if (Panel1.Height < 30) then begin Panel1.Height := 0; end; end; procedure TDocForm.SpTBXSplitter1Moving(Sender: TObject; var NewSize: Integer; var Accept: Boolean); begin Accept := (NewSize > 25); end; のように、OnMoving の Acceptに余裕をもたせて、OnMoved で閾値以下は 0 にする

Delphi RTTI でプロパティ名や型を再帰で取得

イメージ
RTTIを用いて、プロパティの設定値をそのままファイルなどへ保存しようとしたが、項目がTFont等のクラスだったりすると中身を取得する必要があるので、再帰で取得 まぁ、できるにはできたんですが、Parent Child のような互いに参照する項目があると、循環が起きてしまうので、レベル(深さ)制限や除外リストなどが用途によって必要かもしれません また、値がnilの項目は型を特定できないため、配下を参照できません(取得時には問題ないかも) フォームへ Memo1(TMemo) と Button1(TButton)を貼り付けて、作成した ListProperties 関数で Button1 のプロパティを参照しています uses へ System.Rtti を追加してください procedure TForm1.Button1Click(Sender: TObject); begin Memo1.Lines.Clear; ListProperties(Button1); end; procedure TForm1.ListProperties(Obj: TObject; Level: Integer = 0); var RttiContext: TRttiContext; RttiType: TRttiType; RttiProp: TRttiProperty; begin if (Obj = nil) then begin Exit; end; if (Level > 3) then begin // Exit; end; RttiContext := TRttiContext.Create; try RttiType := RttiContext.GetType(Obj.ClassInfo); for RttiProp in RttiType.GetProperties do begin Memo1.Lines.Add(StringOfChar(#9, Level) + RttiProp.Name + ': ' + RttiProp.Property

Delphi の RTTI で record の情報取得(2/2)

Delphi の RTTI(Delphi 2010以降) とジェネリックスを利用して record 型の情報取得 昨日のコード は、取得するだけで書き込む事を考えてなかったので、その辺りを変更 Create時の引数からポインタを保持して、record そのものを変更しに行く これで、record の型と値を放り込んだら、レジストリやIniFileやSQLへの書き込みや、読み込みが可能になるクラスが作れます 独自のクラスを保存したい場合、FieldType の TypeKind へ tkClass が入るので、 if (Value.AsObject is TMyClass) then のようにクラスを判定して処理したり、さらに再帰して中身を分離したりできそう ところで、ジェネリックスで与えられた型を使って、汎用ポインタからキャストって出来ないんですかね var D: T; P: ^T; begin D := P^; end; みたいなのは OK ですが var D: T; P: Pointer; begin P := @D; D := T(P); // NG D := (P as T); // NG D := <T>(P); // NG end; みたいなのは、NGで一方通行なんです 昨日 と似たコード(Value がプロパティに変更され、引数のカッコを変更)で、書き込みをしている procedure TForm1.Button1Click(Sender: TObject); var I: Integer; RecField: TRttiRecordField<TTestRecord>; TestRecord: TTestRecord; S, ValueStr: string; begin TestRecord.Key := 'Hello'; TestRecord.Value := 99; RecField := TRttiRecordField .Create(TestRecord); try for I := RecField.Count - 1 downto 0

Delphi の RTTI で record の情報取得(1/2)

Delphi 2010だったかで、機能追加された RTTI。 クラスなどのフィールド情報などを取得できる ( 2/2は こちら ) 喜んで試してみたんだけど、class だけで record の情報は取得できない様子(できるのかもしれんが) ただ、class メンバの record 型の情報は取れるので、ジェネリックスと絡めて record 型のメンバとデータを取得するクラスを作成してみた(後半のコード) 何がしたかったかというと、データ設定値などを record 型で作成して、レジストリやIniファイルへ保存するようなパターンで、フィールドが増えたときにいちいち保存や読込の所を修正しに行くのが面倒 TInifile を継承して、レコード型を渡すだけで、全て指定セクションに書き込んでちょ、みたいなのを最終的に利用できればよいと思う(SQLとのやりとりなんかにも) Form1 に Button1 と Memo1 を貼って、TTestRecord のメンバと値を列挙する (とりあえず String と Integer の例) TRttiRecordField の Create で、型と実際の値を渡してやれば、あとはメソッドを呼び出すだけです type TTestRecord = record Key: string; Value: Integer; end; procedure TForm1.Button1Click(Sender: TObject); var I: Integer; S: string; RecField: TRttiRecordField<TTestRecord>; TestRecord: TTestRecord; begin TestRecord.Key := 'Hello'; TestRecord.Value := 99; RecField := TRttiRecordField<TTestRecord>.Create(TestRecord); try for I := RecField.Count - 1 downto 0 do begin