年収300万未満こどおじプログラマーブログ

明るい未来は望めない底辺おっさんPGのブログ

【Xamarin・iOS】シミュレータ実行時、「System.Exception 〜MissingEntitlement」で怒られる

f:id:uma-no-kawa:20200128164837j:plain

シミュレータでは、Xamarin.Essentials.SecureStorageを使用すると、上記エラーが発生するようです。

エラーに書かれている通りに修正を行います。

iOSプロジェクトの中にあるEssentials.plistの下記項目にチェックを入れます。

f:id:uma-no-kawa:20200128165211j:plain

その後、iOSプロジェクトの「オプション」>「ビルド」>「iOSバンドル署名」のカスタムエンタイトルメントに先ほど編集したplistを設定します。

f:id:uma-no-kawa:20200128165357j:plain

この際、画像上部の「構成」と「プラットフォーム」がシミュレータ環境としてふさわしいかどうかを確認してください。

以上です。

【Xamarin・iOS】App Store Connect に" ITMS-90338: Non-public API usage"と怒られアップロードできない

Xamarin.iOSApp Store Connectにアプリをアップロードしようとする際


ITMS-90338: Non-public API usage - The app references non-public selectors in XXXXXXX.iOS: applicationWillTerminate, ddSetLogLevel:, localTarget, newSocketQueueForConnectionFromAddress:onSocket:, setOrientation:animated:, socket:didConnectToHost:port:, socket:didReadPartialDataOfLength:tag:, socket:didReceiveTrust:completionHandler:, socket:didWritePartialDataOfLength:tag:, socket:shouldTimeoutReadWithTag:elapsed:bytesDone:, socket:shouldTimeoutWriteWithTag:elapsed:bytesDone:, socketDidCloseReadStream:, socketDidSecure:, terminateWithSuccess, webSocket:didReceiveMessage:, webSocketDidOpen:. If method names in your source code match the private Apple APIs listed above, altering your method names will help prevent this app from being flagged in future submissions. In addition, note that one or more of the above APIs may be located in a static library that was included with your app. If so, they must be removed. For further information, visit the Technical Support Information at http://developer.apple.com/support/technical/


と怒られアップロードできないことがあります。

要するに、

使用してはいけないAPIを使用している

ということです。

解法は恐らく様々ですが、

私の場合はAppDelegate.csの

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    Xamarin.Calabash.Start();
    // 中略...
}

を下記のように変更

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
#if DEBUG
    Xamarin.Calabash.Start();
#endif
    // 中略...
}

以上で問題は解消されました。

【PHP・meyfa/php-svg】imagettftext(): any2eucjp(): invalid code in input string というエラーが出る

meyfa/php-svg 便利ですよね

github.com

今日もこれの話題です。

現象

サーバによっては、

imagettftext(): any2eucjp(): invalid code in input string

というエラーが出る場合があります。

全角スペースなどの一部特殊文字を描画しようとすると発生する様子。

meyfa/php-svgで通常文字列を描画しようとすると下記の様なコードになります。

<?php
(new SVGText("はろー わーるど", $x, $y))->setFont($font)
    ->setSize($fontSize)
    ->setStyle('fill', $color)
    ->setStyle('stroke', $color)
    ->setStyle('stroke-width', $strokeWidth)

上記コード("はろー"と"わーるど"の間に全角スペースがあります)が題のようなエラーが出て正常に動作しない場合は、下記の様にコードを変更します。

<?php
$text = "はろー わーるど";
$text = mb_encode_numericentity($text, array(0x0080, 0xffff, 0, 0xffff), 'UTF-8');
(new SVGText($text, $x, $y))->setFont($font)
    ->setSize($fontSize)
    ->setStyle('fill', $color)
    ->setStyle('stroke', $color)
    ->setStyle('stroke-width', $strokeWidth)

mb_encode_numericentityという関数を使用するようです。

mb_encode_numericentityのドキュメントは下記の通り。

https://www.php.net/manual/ja/function.mb-encode-numericentity.php

また参考までに第一引数、第二引数に関係するユニコードの対応表は、下記の通り

unicode.ninpou.jp

上記例のコードですと0x0080ですので、「€」以降が変換されるわけです。

以上。

【Laravel】一致バリデーションequalを作る

ごく稀に使いたくなるので、用意します。

環境

  • Laravel 5.4
  • PHP 5.6.9

実装

AppServiceProvider.phpに下記を記載します

<?php
namespace App\Providers;

use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // 追記部分
        Validator::extend("equal", function ($attrivute, $value, $parameters, $validator) {
            return $value == $parameters[0];
        });
    }
    /* 省略 */
}

利用時は下記のようにします

例:$request->hogehogeがfugafugaと一致するかどうか

<?php
// 省略
$this->validate($request, ["hogehoge" => "equal:fugafuga"]);

【Xamarin・Fody】List<T>の更新が反映されない

表題の通りです。

環境

  • iOS12.1.4
  • VisualStudio for Mac 8.3.8
  • Xamarin.Forms 4.2.0.848062
  • PropertyChanged.Fody 3.1.3

問題のあるコード

XMLファイル

<!-- 省略 -->
<Picker ItemsSource="{Binding Items}" ItemDisplayBinding="{Binding Name}"/>
<!-- 省略 -->

コンテンツページクラス

using Xamarin.Forms;
using MyApp.Model;

namespace MyApp.Pages
{
    public partial class MyPage : ContentPage
    {
        MyModel model;

        public MyPage()
        {
            InitializeComponent();
            model = new MyModel();
            BindingContext = model;
            model.update();
        }
    }
}

モデル

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace MyApp.Model
{
    public class MyModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public class PickerItems
        {
            public string Name { get; set; }
        }
        public List<PickerItems> Items { get; set; }

        public MyModel()
        {
            Items = new List<PickerItems>();
            Items.Add(new PickerItems() { Name = "1号" });
        }
        
        public function void update()
        {
            Items.Add(new PickerItems() { Name = "2号" });
        }
    }
}

上記コードでは、「1号」は追加されますが、「2号」が追加されません。

List<T>ではなくObservableCollection<T>を使用します。

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace MyApp.Model
{
    public class MyModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public class PickerItems
        {
            public string Name { get; set; }
        }
        public ObservableCollection<PickerItems> Items { get; set; }

        public MyModel()
        {
            Items = new ObservableCollection<PickerItems>();
            Items.Add(new PickerItems() { Name = "1号改" });
        }
        
        public function void update()
        {
            Items.Add(new PickerItems() { Name = "2号改" });
        }
    }
}

【Xamarin】角丸ボタンを作成する

↓こういうボタンを作成します。

f:id:uma-no-kawa:20191120101411j:plain

環境

手順

Xamarinって実はXaml上でcssが使えるんです。

ご存知でしたか?私は知りませんでした。

なので下記のように書くだけで、

<?xml version="1.0" encoding="utf-8"?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MyApp"
    mc:Ignorable="d"
    x:Class="MyApp.Pages.MainPage">
    <!-- 下記のようにCSSを書きます -->
    <ContentPage.Resources>
        <StyleSheet>
            <![CDATA[
                .round-button {
                    border-radius:30;
                }
            ]]>
        </StyleSheet>
    </ContentPage.Resources>
    <!-- CSSここまで -->
    <StackLayout Spacing="0">
        <!-- 下記のようにStyleClass/StyleIdで要素にclass/idを指定します -->
        <Button Text="ログイン" HorizontalOptions="Center" BackgroundColor="red" TextColor="White" WidthRequest="320" HeightRequest="60" FontSize="20" StyleClass="round-button"></Button>
    </StackLayout>
</ContentPage>

角丸が実現できます。

そのほか、利用できるCSSは下記を参照ください。

docs.microsoft.com

【Firebase・iOS・Xamarin】プッシュ通知FCMする

環境

実装準備

1. GoogleDeveloperアカウント関連

前提としてGoogleDeveloperアカウントが必要です。

1-1. TeamIDをメモ

下記URLでTeamIDを確認する

https://developer.apple.com/account/#/membership/

1-2. AuthKeysを取得

下記URLでAuthKeyを作成しダウンロードする(.p8ファイル)。 AuthKeyのIDをメモしておく。

https://developer.apple.com/account/resources/authkeys/list

作成の途中で「Apple Push Notifications service (APNs)」にチェックを入れることを忘れないように

1-3. Identifiersを取得

下記URLでIdentifiersを作成しダウンロード

https://developer.apple.com/account/resources/identifiers/list

作成途中で「Capabilities > Push Notifications」にチェックを入れることを忘れないように

f:id:uma-no-kawa:20191112152542j:plain

2. Firebase関連

Firebaseプロジェクトはあらかじめ作成しておいてください

2-1. GoogleService-info.plistを取得

  • Firebase Console で iOSのアプリを追加し、GoogleService-info.plistを取得

https://console.firebase.google.com

2-2. AuthKeyのアップロード

コンソールサイドバーにある歯車からプロジェクトの設定 > Cloud MessagingでAPNs認証キーを登録します。

その際1-1, 1-2でメモした情報を入力します

3. Xamarin設定関係

3-1 GoogleService-info.plistをコピー

2-1で取得したGoogleService-info.plistをiOSのルートにコピーします。

f:id:uma-no-kawa:20191112153504j:plain

GoogleService-info.plistを右クリック->「ビルドアクション」->「BundleResource」を選択

3-2 GoogleService-info.plistを編集

Xcodeで展開し、IS_GCM_ENABLEキーがtrueであることを確認。trueでない場合はtrueにする。

3-3 Entitlements.plistを編集

下記図のようにPush Notificationsにチェックを入れる

f:id:uma-no-kawa:20191112153738j:plain

3-4 info.plistを編集

下記図のようにリモート通知を許可する

f:id:uma-no-kawa:20191112153857j:plain

実装

Xamarin実装

AppDelegate.csにて下記の実装を行う

using System;
using System.Collections.Generic;
using System.Linq;
using Firebase.CloudMessaging;
using Foundation;
using UIKit;
using UserNotifications;

namespace App.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IMessagingDelegate, IUNUserNotificationCenterDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            Xamarin.Calabash.Start();
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());

            Firebase.Core.App.Configure();
            Messaging.SharedInstance.Delegate = this;

            if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
            {
                // iOS10.0
                UNUserNotificationCenter.Current.Delegate = this;
                var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
                UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
                {
                    Console.WriteLine(granted);
                });
                UIApplication.SharedApplication.RegisterForRemoteNotifications();
            } else
            {
                //iOS9以前 今回の記事ではカバーしない
                //参考:https://github.com/xamarin/GoogleApisForiOSComponents/blob/master/docs/Firebase/CloudMessaging/GettingStarted.md
            }
            return base.FinishedLaunching(app, options);
        }

        [Export ("messaging:didReceiveRegistrationToken:")]
        public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
        {
            //FCMトークンを取得
            Console.WriteLine($"Firebase registration token: {fcmToken}");
        }
    }
}

実機で実行し、通知を許可すると、FCMトークンが取得できることを確認する。

FCMトークン値はメモしておく

FCM送信テスト

Firebaseコンソール -> Cloud Messaging -> Send your first messageでテストを行う。

タイトルとテキストを入力し、「テキストメッセージを送信」をクリック。

先ほど確認したFCMトークンを設定し、テストを行う。

以上