2021年9月29日 星期三

[Q&A] Send image from ionic to asp.net core (IFormFile) web api

 [Q]

We are looking to upload image from ionic to .net core web api. To achieve this we are using file transfer plugin.

So, far we understood that image will be converted into base64. However, what we are looking is how can we sent form data along with multiple image to web api?

Below is the code from ionic side.

HTML code to trigger select image function:

<ion-button fill="clear" expand="full" color="light" (click)="selectImage()">
      <ion-icon slot="start" name="camera"></ion-icon>
      Select Image</ion-button>

Component file code to upload image using ionic camera Plugin:

async selectImage() {
      const actionSheet = await this.actionSheetController.create({
          header: "Select Image source",
          buttons: [{
                  text: 'Load from Library',
                  handler: () => {
                      this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY);
                  }
              },
              {
                  text: 'Use Camera',
                  handler: () => {
                      this.takePicture(this.camera.PictureSourceType.CAMERA);
                  }
              },
              {
                  text: 'Cancel',
                  role: 'cancel'
              }
          ]
      });
      await actionSheet.present();
  }

  takePicture(sourceType: PictureSourceType) {
      var options: CameraOptions = {
          quality: 100,
          sourceType: sourceType,
          saveToPhotoAlbum: false,
          correctOrientation: true
      };

      this.camera.getPicture(options).then(imagePath => {
        this.base64img="data:image/jpeg;base64,"+imagePath;
        this.uploadPic();
      });

  }

Component file code to pass image to web api:

uploadPic() {
        const fileTransfer: FileTransferObject = this.transfer.create();
        let filename = this.base64img.split('/').pop();
        let options: FileUploadOptions = {
            fileKey: "file",
            fileName: filename,
            chunkedMode: false,
            mimeType: "image/jpg",
            params: { 'title': this.imageTitle }
        }

        fileTransfer.upload(this.base64img, '<api endpoint>', options).then(data => {
          alert(JSON.stringify(data));
        }, error => {

          alert("error");
          alert("error" + JSON.stringify(error));
        });
      }

By doing this we are able to get the file in HttpContext.Request.Form.Files, but how can we get this in [FromBody] request parameter in web api? So, that I can get form data as well images to upload.

Also, we have tried by adding only one request parameter in web api, by assuming that the base64 which passed from client side will be received at in request parameter. But this also didn't work, which has given error 'Value cannot be null'.




[A]


You can send base64 data to any server API using HttpClientModule

Just do following changes in your code

Step 1: In app.module.ts

import { HttpClientModule } from '@angular/common/http';

include HttpClientModule in imports

Step 2: In page.ts

import { HttpClient } from '@angular/common/http';

constructor(private httpClient: HttpClient) { }

Initialise HttpClient in the constructor of page.ts

 sendData(base64img,other_data) {
    let _url = "";
    let formData = new FormData();
    formData.append("base64img", base64img);
    formData.append("other_data", other_data);
    this.httpClient.post(_url, formData).subscribe((res) => {
    //res contains server response
    });
  }





from:
https://stackoverflow.com/questions/58429122/send-image-from-ionic-to-asp-net-core-web-api

2021年5月2日 星期日

編譯 iOS 出現 ‘xcodebuild’ requires Xcode 的錯誤訊息

 自己寫的「圖書館多重帳戶」app 一直都只有 Chrome  Android 版本,

今天想來編譯一下 Cordova 的 iOS 版本時,

又遇到了一些和先前遇過不同的問題…

這些是之前編譯與除錯 iOS 時曾遇到的問題:

 

來記錄一下這次遇到的問題吧~

 

1. Cordova 專案中缺少 iOS 平台支援

在執行 cordova build ios 之後,出現了錯誤訊息

The platform “ios” does not appear to have been added to this project:

testuser@localhost ~ $ cordova build --debug ios

(node:16131) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: The platform "ios" does not appear to have been added to this project.

 

這是因為我之前移掉了 ios 的 platform~

執行 cordova platform 可以看到目前專案中只安裝了 android 平台支援:

testuser@localhost ~ $ cordova platform

Installed platforms:
  android 6.2.3
Available platforms:
  browser ~5.0.1
  ios ~4.5.4
  osx ~4.0.1
  windows ~5.0.0
  www ^3.12.0

 

只要把 ios 平台支援加上就好了:

cordova platform add ios

 

2. 找不到完整的 Xcode

繼續執行 cordova build ios,又出現了另一個錯誤訊息

tool ‘xcodebuild’ requires Xcode, but active developer directory

‘/Library/Developer/CommandLineTools’ is a command line tools instance

這個還真的有點搞不懂是在做什麼:

testuser@localhost ~ $ cordova build --debug ios

(node:16169) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

 

不過我這台 Mac 的確是還沒安裝 Xcode…

先到 Mac 的 App Store 搜尋 Xcode 來安裝~

裝好之後,記得要執行一次 Xcode,

它還會繼續安裝其他的元件:

 

註:如果裝好 Xcode 後沒有先執行一次,

執行 cordova build ios 可能會出現找不到模擬器的錯誤訊息,

執行過 Xcode 後就會消失了:

testuser@localhost ~ $ cordova build --debug ios

(node:99278) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Command failed: xcrun simctl list --json
dyld: Library not loaded: /Library/Developer/PrivateFrameworks/CoreSimulator.framework/Versions/A/CoreSimulator
  Referenced from: /Applications/Xcode.app/Contents/Developer/usr/bin/simctl
  Reason: image not found

 

但 Xcode 裝好之後,還是會出現 ‘xcodebuild’ requires Xcode 的錯誤訊息…

查了一下,是說預設的 /Library/Developer/CommandLineTools 目錄下,

並沒有完整的 Xcode,但 cordova build ios 需要的是完整的 Xcode。

因此要執行下面的指令,切換到剛裝好的 Xcode 路徑上:

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

 

這時再執行 cordova build ios,就沒有問題了:

testuser@localhost ~ $ cordova build --debug ios

Building for iPhone X Simulator
......
** BUILD SUCCEEDED **

 



from: https://ephrain.net/cordova-%E7%B7%A8%E8%AD%AF-ios-%E5%87%BA%E7%8F%BE-xcodebuild-requires-xcode-%E7%9A%84%E9%8C%AF%E8%AA%A4%E8%A8%8A%E6%81%AF/

2021年4月9日 星期五

Ionic error message: Unsupported engine package: '@angular/cli@11.1.4'

Error message:
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular/cli@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/architect@0.1101.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/core@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/schematics@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@schematics/angular@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/core@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/schematics@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@schematics/update@0.1101.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/core@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@angular-devkit/schematics@11.1.4',
npm WARN EBADENGINE   required: { node: '>= 10.13.0', npm: '^6.11.0', yarn: '>= 1.13.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@stencil/core@2.5.2',
npm WARN EBADENGINE   required: { node: '>=12.10.0', npm: '>=6.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.5.0', npm: '7.8.0' }
npm WARN EBADENGINE }  



Solution:
$ npm -v
7.5.0

$ npm install --global npm@6

removed 60 packages, changed 194 packages, and audited 436 packages in 30s

3 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

$ npm -v
6.14.11

$ npm install -g @angular/cli
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
/usr/local/bin/ng -> /usr/local/lib/node_modules/@angular/cli/bin/ng

> @angular/cli@11.1.4 postinstall /usr/local/lib/node_modules/@angular/cli
> node ./bin/postinstall/script.js

? Would you like to share anonymous usage data with the Angular Team at Google u
nder
Google’s Privacy Policy at https://policies.google.com/privacy? For more details
 and
how to change this setting, see http://angular.io/analytics. Yes

Thank you for sharing anonymous usage data. If you change your mind, the following
command will disable this feature entirely:

    ng analytics off

+ @angular/cli@11.1.4
added 5 packages from 2 contributors, removed 7 packages and updated 234 packages in 103.594s
————————————————
  

 

2021年3月31日 星期三

如何在應用程式利用Google發通知郵件

1.申請1個Google的信箱。

2.使用應用程式密碼登入帳戶

使用應用程式密碼。

    1. 前往您的 Google 帳戶
    2. 選取 [安全性]。
    3. 選取「登入 Google」底下的 [應用程式密碼]。您可能需要登入。如果您沒有看到這個選項,可能原因如下:
      1. 您的帳戶並未設定兩步驟驗證。
      2. 您目前只設定使用安全金鑰進行兩步驟驗證。
      3. 您使用的是公司、學校或其他機構專用的帳戶。
      4. 您已啟用進階保護功能。
    4. 選擇底部的 [選取應用程式] 並選擇您所使用的應用程式 下一步 選擇 [選取裝置] 並選擇您所使用的裝置 下一步 選取 [產生]。
    5. 按照操作說明輸入應用程式密碼。應用程式密碼是指裝置上黃色列中的 16 位數代碼。
    6. 輕觸 [完成]。
3.參數設定參考
<configuration>
  <system.net>
    <mailSettings>
      <smtp deliveryMethod="Network" from="xxxxx@gmail.com">
        <network defaultCredentials="false" host="smtp.gmail.com" port="587" userName="xxxxx@gmail.com" password="xxxxxxxxxxxxxxxx" enableSsl="true" />
      </smtp>
    </mailSettings>
  </system.net>


2021年3月24日 星期三

關於 RxJS 裡的 BehaviorSubject 可以怎麼用!

 RxJS 裡的 Subject 有 4 種類型,Subject、BehaviorSubject、ReplaySubject 和 AsyncSubject,每一種類型的 Subject 都有各自的特性及使用時機,這次會使用 BehaviorSubject來管理使用者的登入狀態


BehaviorSubject

BehaviorSubject 與一般的 Subject 有什麼不一樣,差別有兩個

  1. BehaviorSubject 可以給予初始值
  2. 每一個 Observer 都可以在註冊的當下,立刻取得目前 BehavoirSubject 的值 (以下皆簡稱為 Subject)

這兩種特性,就非常適合用在使用者登入狀態管理的這種情境

使用情境

使用者登入基本上,狀態就兩種,登入與尚未登入,而每一個頁面都可以在取得該使用者目前的登入狀態。也可以即時知道已登入的使用者登出的時間點。

根據上列的描述,我們會實作一個 UserService,用來執行跟管理使用者的登入,登出行為及狀態。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from "rxjs";

@Injectable()
export class UserService {
isLoginSubject = new BehaviorSubject<boolean>(this.hasToken());

/**
* 如果有取得token,表示使用者有登入系統
* @returns {boolean}
*/
private hasToken() : boolean {
return !!localStorage.getItem('token');
}

/**
* 登入使用者,並通知所有訂閱者
*/
login() : void {
localStorage.setItem('token', 'JWT');
this.isLoginSubject.next(true);
}

/**
* 登出使用者,並通知所有訂閱者
*/
logout() : void {
localStorage.removeItem('token');
this.isLoginSubject.next(false);
}

/**
*
* @returns {Observable<T>}
*/
isLoggedIn() : Observable<boolean> {
return this.isLoginSubject.asObservable();
}
}

Component 的使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Component, OnInit } from '@angular/core';
import { AuthService } from "../auth.service";
import { Observable } from "rxjs";

@Component({
selector: 'app-main-nav',
template: `
<ul>
<li *ngIf="!(isLoggedIn | async)" (click)="authService.login()>
<a>Login</a>
</li>
<li *ngIf="(isLoggedIn | async)" (click)="authService.logout()">
<a>Logout</a>
</li>
</ul>
`
})
export class MainNavComponent implements OnInit {
isLoggedIn : Observable<boolean>;

constructor( public userService : UserService ) {
this.isLoggedIn = userService.isLoggedIn();
}
}

這樣子就完成了一個陽春型的使用者登入狀態管理 service。



參考資料

2021年3月21日 星期日

No pipe found with name 'translate'

 Error message:

error NG8004: No pipe found with name 'translate'.



page module 要作如下配置:

import { TranslateModule } from '@ngx-translate/core';


@NgModule({

  imports: [

TranslateModule

  ],

  exports: [

TranslateModule

  ]

})


If 'ion-title' is an Angular component, then verify that it is part of this module.

 Error message:

1. If 'ion-title' is an Angular component, then verify that it is part of this module.

2. If 'ion-title' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.


page ts 要加 entryComponents:

const tmpModule = NgModule({

         declarations: [tmpCmp],

         imports:[IonicModule],

         entryComponents: [tmpCmp]

    })(class {});


2021年3月20日 星期六

ionic buile error: No provider for LocalNotifications

Error message:

core.js:6140 ERROR NullInjectorError: R3InjectorError(AppModule)[cls_localnotifications -> LocalNotifications -> LocalNotifications -> LocalNotifications]: 

  NullInjectorError: No provider for LocalNotifications!


Soluction:

app.module.ts  add:

import { LocalNotifications } from '@ionic-native/local-notifications/ngx';

providers: [

    LocalNotifications,

]


         

2021年3月16日 星期二

No targets devices/emulators available. 使用模擬器出現異常,無法使用

指令:ionic cordova emulate android 

異常訊息:

[native-run] ERR_NO_TARGET: No targets devices/emulators available. Cannot create AVD because there is no suitable API installation. Use --sdk-info to reveal missing packages and other issues.


avdmanager list avd    --列出所有系統中所有的AVD    

(環境變數中要有 %ANDROID_HOME%\tools\bin 才可以執行)


avdmanager list target --列出目標的AVD


C:\Users\morse>avdmanager list target

Available Android targets:==============] 100% Fetch remote repository...

----------

id: 1 or "android-19"

Name: Android API 19

Type: Platform

API level: 19

Revision: 4

----------

id: 2 or "android-28"

Name: Android API 28

Type: Platform

API level: 28

Revision: 6

----------

id: 3 or "android-29"

Name: Android API 29

Type: Platform

API level: 29

Revision: 4

ionic指定模擬器:

手機

ionic cordova emulate android --target=Nexus_5X_API_26_x86

ionic cordova emulate android --target=Nexus_5X_API_26_x86 --verbose

ionic cordova emulate android --target=Nexus_5X_API_26_x86 --warning-mode all

平板

ionic cordova emulate android --target=Nexus_9_API_27


SDK 管理工具

sdkmanager --install "system-images;android-29;default;x86"


ionic admob enabling test ads

 在開發過程中啟用測試廣告很重要,這樣您就可以在不向Google廣告客戶收費的情況下點擊它們。如果您在未處於測試模式的情況下點擊了太多廣告,則可能會將您的帳戶標記為無效活動。


以下是示例廣告單元,它們針對每種格式指向特定的測試廣告素材:

廣告格式樣本廣告單元ID
應用程式開啟ca-app-pub-3940256099942544/3419835294
橫幅ca-app-pub-3940256099942544/6300978111
插頁式ca-app-pub-3940256099942544/1033173712
插頁式視頻ca-app-pub-3940256099942544/8691691433
獎勵ca-app-pub-3940256099942544/5224354917
獎勵插頁式廣告ca-app-pub-3940256099942544/5354046379
本機高級ca-app-pub-3940256099942544/2247696110
原生高級視頻ca-app-pub-3940256099942544/1044960115




2021年3月15日 星期一

ionic cordova build example

Examples

ionic cordova build android
ionic cordova build android --buildConfig=build.json
ionic cordova build android --prod --release -- -- --gradleArg=-PcdvBuildMultipleApks=true
ionic cordova build android --prod --release -- -- --keystore=filename.keystore --alias=myalias
ionic cordova build android --prod --release -- -- --minSdkVersion=21
ionic cordova build android --prod --release -- -- --versionCode=55
ionic cordova build android --prod --release --buildConfig=build.json
ionic cordova build ios
ionic cordova build ios --buildConfig=build.json
ionic cordova build ios --prod --release
ionic cordova build ios --prod --release -- --developmentTeam="ABCD" --codeSignIdentity="iPhone Developer" --packageType="app-store"
ionic cordova build ios --prod --release --buildConfig=build.json

Execution failed for task ':app:stripDebugDebugSymbols'.

ionic cordova build android 


錯誤訊息:

Execution failed for task ':app:stripDebugDebugSymbols'.

> No version of NDK matched the requested version 21.0.6113669. Versions available locally: 21.3.6528147



解決:

下載對應版本NDK




ionic cordova 改為 AndroidX

修改    \platforms\android\gradle.properties


android.useAndroidX=true
android.enableJetifier=true


Build:

    ionic cordova build android


錯誤訊息:

該項目使用AndroidX依賴項,但未啟用'android.useAndroidX'屬性。在gradle.properties文件中將此屬性設置為true,然後重試。

檢測到以下AndroidX依賴項:

...


解決:

# add plugin to enable AndroidX in the project

cordova plugin add cordova-plugin-androidx


# add plugin to patch existing plugin source that uses the Android Support Library to use AndroidX

cordova plugin add cordova-plugin-androidx-adapter


2021年3月10日 星期三

如何在 ionic 中安裝 capacitor

安裝指令如下: 


npm install @capacitor/android@latest

ionic 的權限設置是記錄在哪?

在Android中,您的應用所需的權限通常在標記的AndroidManifest.xml內部(<manifest>通常在文件底部)定義

例如,這是添加網絡權限的樣子:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.getcapacitor.myapp">
    <activity>
      <!-- other stuff -->
    </activity>

    <!-- More stuff -->

    <!-- Your permissions -->

    <!-- Network API -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

通常,您選擇使用的插件會要求您設置權限。將其添加到此文件中。

[Q&A] Send image from ionic to asp.net core (IFormFile) web api

 [Q] We are looking to upload image from ionic to .net core web api. To achieve this we are using file transfer plugin. So, far we understoo...