【ハルシオンブログ】Unity Cloud Diagnostics を ON にしておくとエラーの収集に便利 その2
こんにちは。
大坂です。
先週の続きです。
ちょっとした使い方を追加で紹介です。
「Crash and Exception Reporting」のページでEditor以外のフィルターを掛けるとリリース後は実機のログのみになるので便利です。
[Add Filter]を押すと、リストが出てくるので[Is Editor]を選択。

[Is Editor]を押して、[+ Add condition]を押す。

Funcitonを[equals]、Valueを[False]にする。

最後に[Apply]を押すと、Editorのレポートが表示されなくなります。

もう1つ紹介。
Unity Plus か Unity Pro. だと エラーの詳細を見た時にある、MedaDataのところに Custom Metadata を追加できます。

コードで「CrashReportHandler.SetUserMetadata」を書いてあげると追加できます。
こんな感じで出ます。

エラーが発生した時に見たいデータを設定しておくと解決に役立つので設定しておくといいですね。
ではまたノシ
大坂です。
先週の続きです。
ちょっとした使い方を追加で紹介です。
「Crash and Exception Reporting」のページでEditor以外のフィルターを掛けるとリリース後は実機のログのみになるので便利です。
[Add Filter]を押すと、リストが出てくるので[Is Editor]を選択。

[Is Editor]を押して、[+ Add condition]を押す。

Funcitonを[equals]、Valueを[False]にする。

最後に[Apply]を押すと、Editorのレポートが表示されなくなります。

もう1つ紹介。
Unity Plus か Unity Pro. だと エラーの詳細を見た時にある、MedaDataのところに Custom Metadata を追加できます。

コードで「CrashReportHandler.SetUserMetadata」を書いてあげると追加できます。
// Custom MetadataにユーザIDを追加()
CrashReportHandler.SetUserMetadata("userId", hogehoge);
こんな感じで出ます。

エラーが発生した時に見たいデータを設定しておくと解決に役立つので設定しておくといいですね。
ではまたノシ
Category: 開発日記(Unity)
【ハルシオンブログ】シーンの遷移をリッチにしよう!シーン遷移のトランジションについて。
こんにちは。
ハルシオンの坂内っす。
おくさん!もう今週で10月になっちゃうそうですよ!
今年もあと3か月しかない!!
さて、Unityのお話。
シーン遷移の際のトランジションについて。
こうやってるよっていう話をしたいと思います。
以前にトランジションのフェードについては書いてます。
【ハルシオンブログ】UnityのuGUIでトランジション 画面遷移とかを少しリッチに!
上記記事はトランジションというかImageをマスクで綺麗にフェードするための方法なので、今日の記事と混ぜることでいい感じのトランジションができるんじゃないかなと思います。
画面遷移のタイミングで画面に遷移エフェクトを行い、シーンを移動するといったことをしようと思った際、シーンにエフェクトをつけてしまうとシーンが切り替わった時点でエフェクトが消えてしまいます。
そのため、シーンとは別にトランジション用のプレハブを作成し、シーンA⇒シーンBといった遷移の際にはトランジションオブジェクトは常に居続ける感じにしています。
まずはトランジションのプレハブを作成

[TransitionManager.cs]
シングルトンのトランジションマネージャーを作成。
フェードインとフェードアウトはまずは作っておきます。
シーンを2個作ります。


シーンのコードはこんな感じ。
ボタンを押したらシーン1の場合はシーン2へ遷移。
シーン2の場合はシーン1へ遷移。
[Scene1.cs]
[Scene2.cs]
ただこれだけです。
これで、シーン1⇔シーン2の遷移の際に、トランジションを行いながら遷移することができます。

もちろん実際に使う際にはダブルクリックの対応とかはやらないといけませんが。
たったこれだけのコードでシーン遷移のトランジションを行うことができます。
ということで、シーン遷移時のトランジションについてでした。
あでゅ~ノシ
ハルシオンの坂内っす。
おくさん!もう今週で10月になっちゃうそうですよ!
今年もあと3か月しかない!!
さて、Unityのお話。
シーン遷移の際のトランジションについて。
こうやってるよっていう話をしたいと思います。
以前にトランジションのフェードについては書いてます。
【ハルシオンブログ】UnityのuGUIでトランジション 画面遷移とかを少しリッチに!
上記記事はトランジションというかImageをマスクで綺麗にフェードするための方法なので、今日の記事と混ぜることでいい感じのトランジションができるんじゃないかなと思います。
画面遷移のタイミングで画面に遷移エフェクトを行い、シーンを移動するといったことをしようと思った際、シーンにエフェクトをつけてしまうとシーンが切り替わった時点でエフェクトが消えてしまいます。
そのため、シーンとは別にトランジション用のプレハブを作成し、シーンA⇒シーンBといった遷移の際にはトランジションオブジェクトは常に居続ける感じにしています。
まずはトランジションのプレハブを作成

[TransitionManager.cs]
using DG.Tweening;
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class TransitionManager : MonoBehaviour
{
public static TransitionManager instance;
private void Awake() {
if (instance == null) {
instance = this;
DontDestroyOnLoad(gameObject);
} else {
Destroy(gameObject);
}
}
[SerializeField] Image imgTransition;
float fadeTime = 0.8f;
public IEnumerator FadeIn() {
imgTransition.DOFade(0f, fadeTime);
yield return new WaitForSeconds(fadeTime);
}
public IEnumerator FadeOut() {
imgTransition.DOFade(1f, fadeTime);
yield return new WaitForSeconds(fadeTime);
}
}
シングルトンのトランジションマネージャーを作成。
フェードインとフェードアウトはまずは作っておきます。
シーンを2個作ります。


シーンのコードはこんな感じ。
ボタンを押したらシーン1の場合はシーン2へ遷移。
シーン2の場合はシーン1へ遷移。
[Scene1.cs]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class Scene1 : MonoBehaviour
{
[SerializeField] TransitionManager transitonObj;
[SerializeField] Button btnNext;
IEnumerator Start() {
Instantiate(transitonObj);
yield return null;
yield return StartCoroutine(TransitionManager.instance.FadeIn());
btnNext.onClick.AddListener(() => StartCoroutine(ChangeScene()));
}
IEnumerator ChangeScene() {
yield return StartCoroutine(TransitionManager.instance.FadeOut());
SceneManager.LoadSceneAsync("scene2");
SceneManager.UnloadSceneAsync("scene1");
}
}
[Scene2.cs]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class Scene2 : MonoBehaviour
{
[SerializeField] Button btnNext;
IEnumerator Start()
{
yield return StartCoroutine(TransitionManager.instance.FadeIn());
btnNext.onClick.AddListener(() => StartCoroutine(ChangeScene()));
}
IEnumerator ChangeScene() {
yield return StartCoroutine(TransitionManager.instance.FadeOut());
SceneManager.LoadSceneAsync("scene1");
SceneManager.UnloadSceneAsync("scene2");
}
}
ただこれだけです。
これで、シーン1⇔シーン2の遷移の際に、トランジションを行いながら遷移することができます。

もちろん実際に使う際にはダブルクリックの対応とかはやらないといけませんが。
たったこれだけのコードでシーン遷移のトランジションを行うことができます。
ということで、シーン遷移時のトランジションについてでした。
あでゅ~ノシ
Category: 開発日記(Unity)
【ハルシオンブログ】Unity Cloud Diagnostics を ON にしておくとエラーの収集に便利 その1
こんにちは。
大坂です。
UnityのServiceで Cloud Diagnostics を ON にしておくと、実機でのエラーも収集してくれるので便利です。
導入方法は
[Window]-[General]-[Service]を開いて「Cloud Diagnostics」をクリックして、OFFのところをクリックして、ONにするだけです。



収集したエラーの確認は、Unityの「GamingSevice」のページを開いて、対象のプロジェクトに変更し、[DevOps]-[Crash and Exception Reporting]で確認できます。

簡単に導入できて実機のエラーも収集してくれるのでリリース後の不具合対応にも役立つのでとりあえず入れておくと便利ですね。
ではまたノシ
大坂です。
UnityのServiceで Cloud Diagnostics を ON にしておくと、実機でのエラーも収集してくれるので便利です。
導入方法は
[Window]-[General]-[Service]を開いて「Cloud Diagnostics」をクリックして、OFFのところをクリックして、ONにするだけです。



収集したエラーの確認は、Unityの「GamingSevice」のページを開いて、対象のプロジェクトに変更し、[DevOps]-[Crash and Exception Reporting]で確認できます。

簡単に導入できて実機のエラーも収集してくれるのでリリース後の不具合対応にも役立つのでとりあえず入れておくと便利ですね。
ではまたノシ
Category: 開発日記(Unity)
【ハルシオンブログ】Hierarchy内で特定のコンポーネントが付いているものを検索
こんにちは。
大坂です。
今日からTGSですね。
行く人は楽しんできてください。行かない人も公式放送とかあったりするのでそちらで楽しんだりできますね。
Hierarchy内で特定のコンポーネントが付いているものを検索したかった。
検索のところにコンポーネントの名前入れるだけなんですけどね。
Audio Source コンポーネントがついたものを検索してみます。

Audio Source の out put がついてたりついてなかったりして音がおかしくなっていたので使ったのでメモ。
何かのお役に立てば!
ではまたノシ
大坂です。
今日からTGSですね。
行く人は楽しんできてください。行かない人も公式放送とかあったりするのでそちらで楽しんだりできますね。
Hierarchy内で特定のコンポーネントが付いているものを検索したかった。
検索のところにコンポーネントの名前入れるだけなんですけどね。
Audio Source コンポーネントがついたものを検索してみます。

Audio Source の out put がついてたりついてなかったりして音がおかしくなっていたので使ったのでメモ。
何かのお役に立てば!
ではまたノシ
Category: 開発日記(Unity)
【ハルシオンブログ】UnityのプロジェクトでATTダイアログを出してみた。え?これでいいの?
こんにちは。坂内っす。
今週は東京ゲームショー2022がありますね。
色々と気になるブースもありますね!
今年は特に行く予定もなく、家で大人しくポケガ3開発してます。
さて、先週はiOSへのビルドで時間食われてました。
その中で、ATTダイアログを出すところでいい感じにはまったので、まとめておきます。
色々なサイトのを試したのですが、結局以下に落ち着きました。
【ATTダイアログ】
iOS14以降からアプリの新規、アップデート時にATT(App Tracking Transparency)の対応が必須になりました。
https://developer.apple.com/jp/news/?id=8rm6injj
こんなの。
これ入れないとリジェクトされるぽいですよ。
では行ってみましょう。
①Assets/Plugins/iOSの下にATTダイアログを出すネイティブコードを作成する
今回は「RequestAttDialog.mm」という名前のコードを作成しました。
[RequestAttDialog.mm]
②ATTダイアログのネイティブコードを呼び出すクラスを作成する
これはUnityのプロジェクト内ならどこでもおk。
[ATTDialog.cs]
③上記で作成したRequestIDFAをアプリ開始のシーンで呼ぶ。
タイトルやスプラッシュのシーンとかあれば、そこのStartなんかで呼んであげればいいです。
④EditorにFrameworkやInfo.plistで設定する必要のあるものをコードで作っておく
Assets/Editorに「PostXcodeBuild.cs」を作成する。
これを作っておけば、XcodeでFrameworkの追加等の手間が省けます。
⑤Unityでビルド
⑥出来上がったUnity-iPhone.xcworkspaceからXcodeを起動して、ビルド
最終的にはこちらでATTダイアログが出るようになりました。
たた、ATTダイアログの戻りを使ったりしてないので、これが正しいのか分からないのが現状…
こうした方がいいよとかそういうのがあったら是非教えてください!
ということで、本日はATTダイアログを出してみた。
では、あでゅ~ノシ
今週は東京ゲームショー2022がありますね。
色々と気になるブースもありますね!
今年は特に行く予定もなく、家で大人しくポケガ3開発してます。
さて、先週はiOSへのビルドで時間食われてました。
その中で、ATTダイアログを出すところでいい感じにはまったので、まとめておきます。
色々なサイトのを試したのですが、結局以下に落ち着きました。
【ATTダイアログ】
iOS14以降からアプリの新規、アップデート時にATT(App Tracking Transparency)の対応が必須になりました。
https://developer.apple.com/jp/news/?id=8rm6injj
こんなの。
これ入れないとリジェクトされるぽいですよ。
では行ってみましょう。
①Assets/Plugins/iOSの下にATTダイアログを出すネイティブコードを作成する
今回は「RequestAttDialog.mm」という名前のコードを作成しました。
[RequestAttDialog.mm]
#import
#import
#import
#ifdef __cplusplus
extern "C" {
#endif
void requestIDFA() {
if (@available(iOS 14, *)){
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
// Tracking authorization completed. Start loading ads here.
// [self loadAd];
}];
}
}
#ifdef __cplusplus
}
#endif
②ATTダイアログのネイティブコードを呼び出すクラスを作成する
これはUnityのプロジェクト内ならどこでもおk。
[ATTDialog.cs]
#if UNITY_IOS
using System.Runtime.InteropServices;
public class ATTDialog
{
[DllImport("__Internal")]
private static extern int requestIDFA();
public static void RequestIDFA()
{
requestIDFA();
}
}
#endif
③上記で作成したRequestIDFAをアプリ開始のシーンで呼ぶ。
タイトルやスプラッシュのシーンとかあれば、そこのStartなんかで呼んであげればいいです。
void Start(){
#if !UNITY_EDITOR && UNITY_IOS
ATTDialog.RequestIDFA();
#endif
}
④EditorにFrameworkやInfo.plistで設定する必要のあるものをコードで作っておく
Assets/Editorに「PostXcodeBuild.cs」を作成する。
//PostXcodeBuild.cs
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using System.Collections;
using System.Collections.Generic;
#if UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif
public class PostXcodeBuild
{
#if UNITY_IOS
private struct InfoplistInfo
{
public string key;
public string value;
public InfoplistInfo(string str1, string str2)
{
key = str1;
value = str2;
}
};
private struct LocalizationInfo
{
public string lang;
public bool isdefault;
public InfoplistInfo[] infoplist;
public LocalizationInfo(string langstr, bool flg, InfoplistInfo[] info)
{
lang = langstr;
infoplist = info;
isdefault = flg;
}
};
private struct CommonInfoPlistInfo
{
public InfoplistInfo[] infoplist;
public CommonInfoPlistInfo(InfoplistInfo[] info)
{
infoplist = info;
}
};
private static LocalizationInfo[] localizationInfo = {
new LocalizationInfo("en", false, new InfoplistInfo[]
{new InfoplistInfo("CFBundleDisplayName", "英語のタイトル"),
new InfoplistInfo("NSUserTrackingUsageDescription", "Please set to Allow to avoid displaying inappropriate advertisements"),
}),
new LocalizationInfo("ja", true, new InfoplistInfo[]
{new InfoplistInfo("CFBundleDisplayName", "日本語のタイトル"),
new InfoplistInfo("NSUserTrackingUsageDescription", "不適切な広告の表示を避けるために”トラッキングを許可”に設定してください"),
})
};
private static string[] skadnetworkitems = new string[] { "cstr6suwn9.skadnetwork" };
static void createInfoPlistString(string pjdirpath, LocalizationInfo localizationinfo)
{
string dirpath = Path.Combine(pjdirpath, "Unity-iPhone Tests");
if (!Directory.Exists(Path.Combine(dirpath, string.Format("{0}.lproj", localizationinfo.lang))))
{
Directory.CreateDirectory(Path.Combine(dirpath, string.Format("{0}.lproj", localizationinfo.lang)));
}
string plistpath = Path.Combine(dirpath, string.Format("{0}.lproj/InfoPlist.strings", localizationinfo.lang));
StreamWriter w = new StreamWriter(plistpath, false);
foreach (InfoplistInfo info in localizationinfo.infoplist)
{
string convertedval = System.Text.Encoding.UTF8.GetString(
System.Text.Encoding.Convert(
System.Text.Encoding.Unicode,
System.Text.Encoding.UTF8,
System.Text.Encoding.Unicode.GetBytes(info.value)
)
);
w.WriteLine(string.Format(info.key + " = \"{0}\";", convertedval));
}
w.Close();
}
static void addknownRegions(string pjdirpath, LocalizationInfo[] info)
{
string strtmp = "";
string pjpath = PBXProject.GetPBXProjectPath(pjdirpath);
foreach (LocalizationInfo infotmp in info)
{
strtmp += "\t\t" + infotmp.lang + ",\n";
}
strtmp += "\t\t);\n";
StreamReader r = new StreamReader(pjpath);
string prjstr = "";
string linetmp = "";
while (r.Peek() >= 0)
{
linetmp = r.ReadLine();
if (linetmp.IndexOf("knownRegions") != -1)
{
prjstr += linetmp + "\n";
prjstr += strtmp;
while (true)
{
linetmp = r.ReadLine();
if (linetmp.IndexOf(");") != -1)
{
break;
}
}
}
else
{
prjstr += linetmp + "\n";
}
}
r.Close();
StreamWriter sw = new StreamWriter(pjpath, false);
sw.Write(prjstr);
sw.Close();
}
static void addLocalizationInfoPlist(string pjdirpath, LocalizationInfo[] info)
{
string plistPath = Path.Combine(pjdirpath, "Info.plist");
PlistDocument plist = new PlistDocument();
plist.ReadFromFile(plistPath);
var array = plist.root.CreateArray("CFBundleLocalizations");
foreach (LocalizationInfo infotmp in info)
{
array.AddString(infotmp.lang);
}
var rootDict = plist.root;
foreach (LocalizationInfo infotmp in info)
{
if (infotmp.isdefault)
{
foreach (InfoplistInfo pinfo in infotmp.infoplist)
{
string convertedval = System.Text.Encoding.UTF8.GetString(
System.Text.Encoding.Convert(
System.Text.Encoding.Unicode,
System.Text.Encoding.UTF8,
System.Text.Encoding.Unicode.GetBytes(pinfo.value)
));
rootDict.SetString(pinfo.key, convertedval);
}
}
}
plist.WriteToFile(plistPath);
}
static void addSkAdNetworkItems(string pjdirpath, string[] skadvallist)
{
string plistPath = Path.Combine(pjdirpath, "Info.plist");
PlistDocument plist = new PlistDocument();
plist.ReadFromFile(plistPath);
if (skadvallist != null)
{
var array = plist.root.CreateArray("SKAdNetworkItems");
foreach (string value in skadvallist)
{
PlistElementDict dict = array.AddDict();
dict.SetString("SKAdNetworkIdentifier", value);
}
}
plist.WriteToFile(plistPath);
}
static void addAppTrackingTransparency(string pathToBuiltProject)
{
string pbxProjectPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
PBXProject pbxProject = new PBXProject();
pbxProject.ReadFromFile(pbxProjectPath);
string targetGuid = pbxProject.GetUnityFrameworkTargetGuid();
pbxProject.AddFrameworkToProject(targetGuid, "AppTrackingTransparency.framework", true);
pbxProject.WriteToFile(pbxProjectPath);
}
[PostProcessBuild]
public static void SetXcodePlist(BuildTarget buildTarget, string pathToBuiltProject)
{
if (buildTarget != BuildTarget.iOS)
{
return;
}
foreach (LocalizationInfo entry in localizationInfo)
{
/* add infoplist.string */
createInfoPlistString(pathToBuiltProject, entry);
}
/* add knownregions to project */
addknownRegions(pathToBuiltProject, localizationInfo);
/* add localization to infoplist */
addLocalizationInfoPlist(pathToBuiltProject, localizationInfo);
/* add addSkAdNetworkItems */
addSkAdNetworkItems(pathToBuiltProject, skadnetworkitems);
/* add AppTrackingTransparency */
addAppTrackingTransparency(pathToBuiltProject);
}
#endif
}
これを作っておけば、XcodeでFrameworkの追加等の手間が省けます。
⑤Unityでビルド
⑥出来上がったUnity-iPhone.xcworkspaceからXcodeを起動して、ビルド
最終的にはこちらでATTダイアログが出るようになりました。
たた、ATTダイアログの戻りを使ったりしてないので、これが正しいのか分からないのが現状…
こうした方がいいよとかそういうのがあったら是非教えてください!
ということで、本日はATTダイアログを出してみた。
では、あでゅ~ノシ
Category: 開発日記(Unity)
【ハルシオンブログ】配列の要素を範囲指定で取得する
こんにちは。
大坂です。
配列の要素を範囲指定で取得する方法です。
C# 8.0 以降から使えるみたいですね。
コード。
結果。

何かの時に使ってみてくださいまし。
ではまたノシ
大坂です。
配列の要素を範囲指定で取得する方法です。
C# 8.0 以降から使えるみたいですね。
コード。
int[] test = new int[] { 0, 1, 2, 3, 4, 5 };
// 要素[1]から最後まで 1,2,3,4,5
Debug.Log(string.Join(",", test[1..]));
// 最初から要素[4]まで 0,1,2,3
Debug.Log(string.Join(",", test[..4]));
// 最初から最後の1つ前の要素まで 1,2,3,4
Debug.Log(string.Join(",", test[1..^1]));
結果。

何かの時に使ってみてくださいまし。
ではまたノシ
Category: 開発日記(Unity)
【ハルシオンブログ】uGUIのImageをOffsetを使用して無限スクロールする方法。
もう気が付けば9月ですね。
ほんとしらないうちに1年が残り3か月になりました。
やばばっ!坂内っす。
ポケガ3今年中に出さないといけないのに…もう時間が…
さて、Unityのお話。
横スクロールアクションとか、それ以外でも絵を無限スクロールする場合ってあるじゃないですか。
もちろん絵自体を動かして端っこまでスクロールしたら元に戻すという方法でできるんですが、絵を動かさないでやる方法もあるぽいです。
あ、uGUIのImageでの話です。
やり方は簡単で、Offsetをいじってスクロールさせてるように見せる方法です。
Image.materialについているOffsetを動かします。
Dotweenだとこんな感じ
DOOffsetで(3.0)まで5秒かけてオフセットを動かします。

こんな感じで動かすことができます。
DoTweenを使わない場合でも、UpdateにてOffsetを動かせば動きます。
ということで、ImageのスクロールをOffsetを使って行う方法でした。
では、あでゅ~ノシ
ほんとしらないうちに1年が残り3か月になりました。
やばばっ!坂内っす。
ポケガ3今年中に出さないといけないのに…もう時間が…
さて、Unityのお話。
横スクロールアクションとか、それ以外でも絵を無限スクロールする場合ってあるじゃないですか。
もちろん絵自体を動かして端っこまでスクロールしたら元に戻すという方法でできるんですが、絵を動かさないでやる方法もあるぽいです。
あ、uGUIのImageでの話です。
やり方は簡単で、Offsetをいじってスクロールさせてるように見せる方法です。
Image.materialについているOffsetを動かします。
Dotweenだとこんな感じ
imgBg.material.DOOffset(new Vector2(3f, 0f), 5f).SetLoops(-1, LoopType.Incremental).SetEase(Ease.Linear);
DOOffsetで(3.0)まで5秒かけてオフセットを動かします。

こんな感じで動かすことができます。
DoTweenを使わない場合でも、UpdateにてOffsetを動かせば動きます。
private void Update() {
imgBg.material.mainTextureOffset += new Vector2(Time.deltaTime * 1f, 0f);
}
ということで、ImageのスクロールをOffsetを使って行う方法でした。
では、あでゅ~ノシ
Category: 開発日記(Unity)
【ハルシオンブログ】Unityでクリップボードに文字列を設定する
こんにちは。
大坂です。
Unityでクリップボードに文字列を設定したかったので、その方法。
「GUIUtility.systemCopyBuffer」に設定するだけなのですが。
一応こんな感じ。

※画像をクリックすると動きます。
ちゃんとクリップボードにコピーされて、ペーストも出来てます。
IDとかをコピーしてあげると入力間違いなどがなくなるかもしれませんね。
ではまたノシ
大坂です。
Unityでクリップボードに文字列を設定したかったので、その方法。
「GUIUtility.systemCopyBuffer」に設定するだけなのですが。
一応こんな感じ。
public SuperTextMesh text;
public void OnClickSetClipboard()
{
GUIUtility.systemCopyBuffer = text.text;
}

※画像をクリックすると動きます。
ちゃんとクリップボードにコピーされて、ペーストも出来てます。
IDとかをコピーしてあげると入力間違いなどがなくなるかもしれませんね。
ではまたノシ
Category: Androidアプリ紹介
| h o m e |