「開発」カテゴリーアーカイブ

StoreKit2でシンプルな課金処理 第7回

今回は購入情報の復元(リストア)処理を行います。

※裏作業でSwiftUIにより、UI上部に”購入情報の復元(リストア)”のリンクを追加しました。課金処理の範囲外になるので「SwiftUI」の記述は詳しく行いませんが、第4回で紹介したAppleのサンプルコードが参考になると思います。

もちろんエラー処理は必要になりますが、購入情報の復元(リストア)処理を行うコードは、基本的に以下の1行だけです!

let result = try? await AppStore.sync()

課金アイテムの取得、課金処理、に続いて今回も1行だけです!

このコードが実行されると、ログインしているAppleIDに紐づいた課金情報が復元されるはずです。ログインしていない場合、ログインを促されると思います。

復元後、UIが更新されるはずですが、サンプルコードにはUIを更新するコードが一見、見当たりません。

おそらく、以下の

updateListenerTask = listenForTransactions()

このコードにより、トランザクションリスナーが開始されているため、課金関連処理が行われるとこのリスナーに検知されてUIが自動で変わる仕組みだと思います。(もし違ったら、詳しい方、コメント欄で教えてください!)

心配な場合は、リストア後にUIを更新するコードを念のため書いておくと良いかと思います。


以上、第1回から今回までで、課金に必要な処理は一通り説明しました。少し前までは、課金処理はとても複雑・面倒で、手を出しにくかった開発者の方も多かったかと思います。特に個人開発者の場合、できれば余分な実装に手間をかけたく無いですよね。

今回、StoreKit2で手軽に課金処理を実装可能になりましたので、いままで手を出せなかった方もどんどん手を出していただければと思います!

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

StoreKit2でシンプルな課金処理 第6回

今回は課金アイテムの購入処理を行います。

※実は裏作業で、「SwiftUI」により課金用のUIを作り込みました。課金処理の範囲外になるので「SwiftUI」の記述は詳しく行いませんが、第4回で紹介したAppleのサンプルコードが参考になると思います。

価格が表記されたボタン押下時に課金処理コードを記述します。

もちろんエラー処理は必要になりますが、基本的に課金処理を行うコードは以下の1行だけです。

let result = try await item.purchase()

※”item” は前回取得した課金アイテムです。

このコードが実行されると、

上記の画像のように、課金アイテムの詳細表示と、購入を促すUIが自動で表示されます。

以上です!

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

あとは、購入済みアイテムの場合、価格ボタンを購入済みと分かる表示に切り替える処理などが必要ですが、この部分も第4回で紹介したAppleのサンプルコード(function isPurchasedの部分)が参考になると思います。

Appleのサンプルコードは一見コード量が多いですが、課金を行うStoreKit2の中核部分は本当にシンプルなコードです。

UIの部分は皆さん好みがあると思いますので、Appleのサンプルコードを参考に独自に実装していただければと思います。

次回は、”リストア”処理を行います!!

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

Javascript と PHP での iOS(iPad)判定

iOS13以降、HTTP_USER_AGENTだけではiPadとPCの区別がつかなくなりました。

これは、9.7インチ以上のiPadの場合にHTTP_USER_AGENTに”iPad”の文字列が含まれなくなり、PCのブラウザ(MacのSafari)からのアクセスとほぼ同じになるケースが発生したからです。

PHPの場合、以前は以下のようなコードでiOS判定が可能でしたが、現在は無理です。

function is_ios() {
    $ua = $_SERVER['HTTP_USER_AGENT'];
    // iOSと判定する文字リスト
    $ua_list = array('iPhone', 'iPad', 'iPod');
    foreach ($ua_list as $ua_smt) {
        if (strpos($ua, $ua_smt) !== false) {
           return true;
        }
    } return false;
}

Javascript ならば、HTTP_USER_AGENTに加えて ‘ontouchend’ なども利用する事で判別可能です。

const ua = window.navigator.userAgent.toLowerCase();
const isIOS = ua.indexOf("iphone") >= 0 
   || ua.indexOf("ipad") >= 0 
   || (ua.indexOf('macintosh') > -1 
       && 'ontouchend' in document) /* iPad */
   || ua.indexOf("ipod") >= 0;

PHP内で判定するには、JavascriptなどからPHPに判定済みの情報を渡すことが必要です。

2022年2月現在、Mac、Windows、iPadからのHTTP_USER_AGENTは以下となります。

[Mac の Safari] と [iPad(9.7インチ以上)の Safari] の違いがほぼ無いことが確認出来ます。

[Mac の Safari]
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15:

[Mac の Chrome]
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36

[Windows の Chrome]
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36

[11インチiPad Pro(第2世代) の Safari]
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15

[11インチiPad Pro(第2世代) の Chrome]
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) Mozilla/5.0 (iPad; CPU OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/97.0.4692.84 Mobile/15E148 Safari/604.1

[iPad mini(第6世代) の Safari]
Mozilla/5.0 (iPad; CPU OS 15_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Mobile/15E148 Safari/604.1

StoreKit2でシンプルな課金処理 第5回

今回は、課金アイテムの取得と表示を行ないます。

課金アイテムは第3回でApp Store Connect上に定義しましたが、これを利用しようとするとSandbox環境でテスト用アカウントを利用する必要があり面倒です。

そこで、第4回のサンプルでも利用されている、ローカルでテストできるようにする仕組み(StoreKit Testing)を用います。

Xcodeのプロジェクトから「New File …」「StoreKit Configuration File」を選択、ファイル名を決めて「Create」で課金アイテム用ファイルを作成します。

作成したファイルを選択後「+」を押して、「Add Auto-Renewable Subscription」 (定期購読型) を追加します。

サブスクリプショングループも、第3回での設定と同じにします。

その他の設定も第3回での指定と同じにします。

課金単位を ¥ にするためには、StoreKit の設定ファイルを選択した状態で、メニュー「Editor」から「Default Storefont」や「Default localization」を選択して「Japan(JPY)」や「Japanese」を選択してください。

あとは「StoreKit Testing」を有効にするために、第4回で行なった手順1〜4の設定を行ってください。

これで準備は完了です。

1行で課金アイテムを取得出来ます。

let items = try await Product.products(for: ["uka.apple.textmanga_favo_120_month", "uka.apple.textmanga_adoff_120_month"])

(広告オフのアイテムも追加したので、2つのアイテムを取得しています)

上の画像は、取得した配列から “displayName” を「SwiftUI※」で表示したものです。

※課金処理の範囲外になるので「SwiftUI」の記述は詳しく行いませんが、以下のようなコードで表示しました。

List(items) { item in
    Text(item.displayName)
}

表示部分は、第4回で紹介したAppleのサンプルコードをどんどんパクりましょう。

次回は課金アイテムの購入処理を行います!!

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

StoreKit2でシンプルな課金処理 第4回

課金処理の実装は、昨年実施された WWDC21 でStoreKit2紹介時にサンプルとして利用されたプロジェクトを参考に行います。

開発元のAppleが紹介しているサンプルなので、利用するコードとしては最高です。

このページのDownloadボタンからサンプルプロジェクトを取得してください。

ダウンロードして解凍後、SKDemo.xcodeprojを開いてプロジェクトを立ち上げます。

プロジェクト実行前に、このページの手順1〜4の設定を行わないと課金アイテムが表示されないので注意してください。

下記画像の赤部分です。

設定後、実行すれば、サンプルプロジェクトが正常に動作します。

次回からはこのプロジェクトを元に、自分のプロジェクトへ自動更新サブスクリプションの部分だけを移植、調整していくこととします。

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

第5回へ続きます。

StoreKit2でシンプルな課金処理 第3回

前回に引き続き、事前の設定作業を行なっていきます。


下記6箇所の設定を行います。

1.まずは、一番上に水色の背景色で表示されている「ローカライゼーションを追加」の文字をクリックします。プルダウンが表示されるので “日本語” を選択します。

「サブスクリプショングループ表示名」は、下記画像の赤丸部分の箇所で表示されます。ここでは “テキスト漫画サブスクリプション” としました。

「App名表示オプション」は、上記のサブスクリプショングループ表示名と共に表示される名前で、そのままでもOKです。右上の「保存」ボタン押下後、元の画面に戻ります。

2.次に「サブスクリプション期間」を設定します。1ヶ月ごとに¥120円としたいので、ここでは “1ヶ月” をプルダウンから選択しました。

3.「サブスクリプション価格」の右にある「+」をクリックし、価格を決定します。テキスト漫画は日本向けに売るので、通貨は “JPY – 日本 円”、価格は “¥120” を選択し、「次へ」をクリックします。

他の国の価格は、上記で選択した価格をベースに自動でセットされます。必要に応じて調整後「作成」をクリックします。

4.次は「ローカライゼーション」の右にある「+」をクリックします。プルダウンが表示されるので “日本語” を選択します。

「サブスクリプション表示名」はApp Store に表示される App 内課金の名前です。ここでは “お気に入り(¥120/月)” としました。

後日追記:サブスクリプション表示名に価格情報を含めてはいけません。リジェクト喰らいました・・・

説明欄には、このサブスクリプションで実現可能な機能を記述します。文字数制限があるため簡潔に記述します。

5.次に、これは任意ですが、アプリ内課金用のイメージを指定します。

画像は 1024 x 1024 で指定します。下のチェックボックスをオンにすると、アプリをインストールしていないユーザがアプリストアでこのアプリを見たときに、どんなことが課金で実現できるのか確認できます。

6.最後に、「審査に関する情報」を設定します。

アプリ内課金で実現可能な機能を、スクリーンショットと共に文章での説明を行います。審査で利用されます。

(あまりにしょぼい機能だとリジェクトを喰らうと思います。自動更新サブスクリプションは特にそうだと思います・・・)

上記画像のようにステータスが「送信準備完了」となればOKです!(広告非表示のアプリ内課金も追加しました)

ついでに、上記画像右上の「App 用共用シークレット」をクリックして、あとで利用する「App用共有シークレット」のコードを生成しておきましょう。


以上で、App Store Connectでの設定はほぼ終わりました!

次回は Xcode を利用しての実装作業に入ります!!

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

第4回へ続きます。

StoreKit2でシンプルな課金処理 第2回

第2回は、事前準備のため、App Store Connectで必要な設定を行なっていきます。誰にでもわかるよう、ログイン画面から操作手順を解説していきます。

※アプリ開発経験者向けの課金処理に関する解説です。


1.App Store Connectにログインします。

2.「契約/税金/口座情報」をクリックします。

3.「有料App」のステータスが「アクティブ」になっていることを確認します。

※上記のようになっていなければ、「有料App」の文字をクリックして、口座情報などを正しく設定します。

4.App Store Connectログイン直後の画面に戻って「マイApp」をクリックします。

5.これから課金処理を実装する、あなたのアプリをクリックします! (※初回バージョンからアプリ内課金を実装する場合は8へ)

6.iOS App の右横の「+」をクリックします。

7.新しいバージョンを入力します。このバージョンからアプリ内課金が有効になります。

8.アプリ画面の左下にあるApp内課金から「管理」をクリックし、App内課金 (0) の右側にある「+」をクリックします。

9.課金タイプを選択します。今回は “自動更新サブスクリプション” を選択します。

10.「参照名」と「製品ID」を入力します。

「参照名」はApp Store Connect上のみで表示されます。自分があとで見て分かりやすい名前をつければ大丈夫です。作成後に変更可能です。

「製品ID」はあとで変更出来ません。他とかぶらない一意のIDを指定します。アプリの識別IDに加えて機能名や金額を指定すると良いと思います。

11.サブスクリプショングループを作成します。

「サブスクリプショングループ参照名」は、サブスクリプションの管理単位で、通常1つのアプリに対して1つあれば良いようです。App Store Connectおよび「売上とトレンド」のレポートでのみ表示されます。App Storeには表示されません。

1〜11の手順が終わると、下記のような画面になります。

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

長くなってきたので、第3回へ続きます。

StoreKit2でシンプルな課金処理 第1回

あけましておめでとうございます。本年もよろしくお願いいたします。

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

本年2022年はiPhoneアプリのテキスト漫画に課金処理を実装していきたいと思います。2022年1月時点で最新の Xcode (13.2.1) をベースに、iOS15で登場したStoreKit2を利用して誰でも確実に課金処理を実装できるよう、連載形式で少しずつ解説していきます。

※アプリ開発経験者向けの課金処理に関する解説です。

テキスト漫画には、既に本連載の方法で月額課金を実装してリリース済みです。


早速ですが、第1回はアプリ内課金の種類を説明します。

アプリ内課金には

1.消耗型
2.非消耗型
3.自動更新サブスクリプション
4.非自動更新サブスクリプション

の4種類があります。

1の消耗型は皆さん大好きなガチャを回すため、ゲーム内通貨を購入する際に利用されます。1回使ったら戻ってきません。お金は大切にしましょう。

2の非消耗型は、1回購入すればアカウントに紐づいて一生涯使い続けられるものです(アプリが無くならなければ)。アプリの広告をオフにする機能や、永続して使い続けられる非消耗型アイテム購入などがあります。

3の自動更新サブスクリプションは、キャンセルするまで継続的に課金されるタイプです。課金している間だけコンテンツへのアクセスが有効になったりします。ビデオ、音楽、記事、クラウドストレージなどへのアクセス権が一例です。課金をやめると利用不可になります。

4の非自動更新サブスクリプションには、シーズンパスなどがあります。自動的に更新されないため、都度購入する必要があります。

今回、テキスト漫画では3の自動更新サブスクリプションを実装予定です。現時点で結構な数のテキスト漫画が存在するため、その中から自分の気に入ったテキスト漫画だけを

お気に入り

に追加し、お気に入りだけを閲覧できる画面を実装します。

(੭ ˃̣̣̥ ω˂̣̣̥)੭ु⁾⁾

・・

・・・え?2の非消耗型でいいんじゃないかって?

ごめんなさい、サーバー代を稼がせてください。

サーバー代は継続してかかるんです。

     -ーー ,,_
   r'”      `ヽ,__
   \       ∩/ ̄ ̄ ヽつ
  ノ ̄\ /”ヽ/ ”   ノ   ヽi
 |  \_)\ .\    ・  ・ |\
 \ ~ )     \ .\_  ( _●_)\_つ
    ̄       \_つ

第2回へ続く・・・

M1 Mac で arm64版のhomebrewとnode(nodebrew) 2021年4月版

買ったばかりのM1 Macにarm64版のhomebrewとnode(nodebrew)をサクッと入れて行きます。

思ったよりさっくり入りました。

トラブルを恐れて、血の滲む思いで4ヶ月買うのを我慢

して良かったです。

homebrew

homebrewはApple M1 チップに正式対応済で、公式通りのインストール方法で良いようです。

% /bin/bash -c “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)”

インストール完了後、パスを通します。

% echo ‘eval “$(/opt/homebrew/bin/brew shellenv)”‘ >> /Users/name/.zprofile
% eval “$(/opt/homebrew/bin/brew shellenv)”

インストールされたバージョンを確認します。

% brew –version
Homebrew 3.0.11
Homebrew/homebrew-core (git revision 4dffd6ddcf; last commit 2021-04-09)

node(nodebrew)

nodeはv15.3.0以降のソースからコンパイルすればarm64版が使えるようです。

% brew install nodebrew
% nodebrew -v
nodebrew 1.0.1
% vim $(which nodebrew)

コンパイル前に vim $(which nodebrew) で以下箇所を修正して保存します。

sub system_info {
my $arch;
my ($sysname, $machine) = (POSIX::uname)[0, 4];
if ($machine =~ m/x86_64|arm64/) { // arm64を条件に追加
$arch = ‘arm64’; // arm64に変更

ホームに移動後、ディレクトリを作成します。その後、ls-remoteでリモート管理されているバージョンを確認します。

% cd ~
% mkdir -p ~/.nodebrew/src
% nodebrew ls-remote

確認後、入れたいバージョンをビルドしてそのバージョンに切り替えます。また、パスを通します。

% nodebrew compile v15.14.0
% nodebrew use v15.14.0
% echo “export PATH=$HOME/.nodebrew/current/bin:$PATH” >> ~/.zprofile
% source ~/.zprofile

バージョンを確認します。

% node -v
v15.14.0

       c⌒っ゚Д゚)っ
M1 Mac mini [16GB/1TB]

Oracle DYNにドメイン名を停止された話

先月2019/6/25に、自作iOSアプリ(側ネイティブアプリなど)およびそのサポートサイトである本サイトに長年利用していたドメイン名がブロックされました。DynDNSの時代から使っていたため、かれこれ15年以上利用していました。

事前警告など全くありません。なんの前触れもなくいきなり止められました。

停止した理由をOracle Dynに問い合わせましたが、しばらく返事がありませんでした。

10日後に、やっと返事がありました。返事は後にも先にもこれだけです。

Hello,

Thank you for contacting the Oracle Dyn Abuse team,

We have received multiple complaints against the hostname in your account, “ukaapple.selfip.com”. As your account has been identified as violating our AUP, it has been terminated. At this time your account will not be reinstated. Your account has also been refunded for current eligible services. For more information about our AUP please visit http://dyn.com/legal/acceptable-use-policy/

Oracle Dyn Abuse Team
abuse@dyn.com

複数件の苦情が入ったらしいです。

しかし、どんな苦情があって、どんな基準に違反したのか全くわからず、対処のしようがありません。

リンク先のAUPの規約を読むとわかるのですが、明確な基準はありません。Oracleの恣意的な判断で自由に決められるもので、あって無いような規約です。

どのような違反があったのか教えてくれと再度問い合わせましたが、それから今日まで返事がありません。もうすぐ1ヶ月経ちます。

Oracleの内部的な実情はわからず推測ですが、おそらく個人相手の商売は金にならないから軽視しているのでしょう。

問い合わせの返事が来るまでの期間や返事の内容を見ていると、サポートの体を成していません。

ドメイン名の回復が見込めなくなったため、新しいドメイン名を取得してアプリなどを改修することになりました。

かなりの改修コストがかかります。この改修コストをかけるなら、1本でも新しいアプリを開発したいところです。

Oracleのやっていることはほとんど犯罪だと思うのですが、どう対処すれば良いですかね?

個人で裁判するのはいろんな面で難しいし、消費者センターに駆け込む訳にも行かないし・・・

個人で出来ることは、なるべくOracleの息がかかったサービスは使わないくらいですかね・・・